VolumeShaper.h revision 10cbff139360f3f642e0e3b3ccf2d463dbed22cf
19fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung/* 29fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * Copyright 2017 The Android Open Source Project 39fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * 49fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * Licensed under the Apache License, Version 2.0 (the "License"); 59fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * you may not use this file except in compliance with the License. 69fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * You may obtain a copy of the License at 79fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * 89fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * http://www.apache.org/licenses/LICENSE-2.0 99fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * 109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * Unless required by applicable law or agreed to in writing, software 119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * distributed under the License is distributed on an "AS IS" BASIS, 129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * See the License for the specific language governing permissions and 149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * limitations under the License. 159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung */ 169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#ifndef ANDROID_VOLUME_SHAPER_H 189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#define ANDROID_VOLUME_SHAPER_H 199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <list> 219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <math.h> 229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <sstream> 239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <binder/Parcel.h> 259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <media/Interpolator.h> 269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <utils/Mutex.h> 279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <utils/RefBase.h> 289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#pragma push_macro("LOG_TAG") 309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#undef LOG_TAG 319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#define LOG_TAG "VolumeShaper" 329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// turn on VolumeShaper logging 349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#if 0 359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#define VS_LOG ALOGD 369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#else 379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#define VS_LOG(...) 389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#endif 399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungnamespace android { 419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// The native VolumeShaper class mirrors the java VolumeShaper class; 439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// in addition, the native class contains implementation for actual operation. 449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// 459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// VolumeShaper methods are not safe for multiple thread access. 469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// Use VolumeHandler for thread-safe encapsulation of multiple VolumeShapers. 479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// 489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// Classes below written are to avoid naked pointers so there are no 499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// explicit destructors required. 509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungclass VolumeShaper { 529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungpublic: 539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung using S = float; 549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung using T = float; 559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung static const int kSystemIdMax = 16; 579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // VolumeShaper::Status is equivalent to status_t if negative 599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // but if non-negative represents the id operated on. 609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // It must be expressible as an int32_t for binder purposes. 619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung using Status = status_t; 629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung class Configuration : public Interpolator<S, T>, public RefBase { 649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung public: 659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung /* VolumeShaper.Configuration derives from the Interpolator class and adds 669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * parameters relating to the volume shape. 679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung */ 689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // TODO document as per VolumeShaper.java flags. 709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // must match with VolumeShaper.java in frameworks/base 729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung enum Type : int32_t { 739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung TYPE_ID, 749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung TYPE_SCALE, 759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung }; 769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // must match with VolumeShaper.java in frameworks/base 789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung enum OptionFlag : int32_t { 799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung OPTION_FLAG_NONE = 0, 809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung OPTION_FLAG_VOLUME_IN_DBFS = (1 << 0), 819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung OPTION_FLAG_CLOCK_TIME = (1 << 1), 829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung OPTION_FLAG_ALL = (OPTION_FLAG_VOLUME_IN_DBFS | OPTION_FLAG_CLOCK_TIME), 849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung }; 859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // bring to derived class; must match with VolumeShaper.java in frameworks/base 879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung using InterpolatorType = Interpolator<S, T>::InterpolatorType; 889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Configuration() 909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : Interpolator<S, T>() 919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mType(TYPE_SCALE) 929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mOptionFlags(OPTION_FLAG_NONE) 939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mDurationMs(1000.) 949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mId(-1) { 959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 9710cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung Configuration(const Configuration &configuration) 9810cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung : Interpolator<S, T>(*static_cast<const Interpolator<S, T> *>(&configuration)) 9910cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung , mType(configuration.mType) 10010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung , mOptionFlags(configuration.mOptionFlags) 10110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung , mDurationMs(configuration.mDurationMs) 10210cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung , mId(configuration.mId) { 10310cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung } 10410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung 1059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Type getType() const { 1069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mType; 1079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t setType(Type type) { 1109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung switch (type) { 1119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung case TYPE_ID: 1129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung case TYPE_SCALE: 1139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mType = type; 1149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return NO_ERROR; 1159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung default: 1169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("invalid Type: %d", type); 1179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return BAD_VALUE; 1189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung OptionFlag getOptionFlags() const { 1229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mOptionFlags; 1239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t setOptionFlags(OptionFlag optionFlags) { 1269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if ((optionFlags & ~OPTION_FLAG_ALL) != 0) { 1279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("optionFlags has invalid bits: %#x", optionFlags); 1289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return BAD_VALUE; 1299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mOptionFlags = optionFlags; 1319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return NO_ERROR; 1329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung double getDurationMs() const { 1359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mDurationMs; 1369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void setDurationMs(double durationMs) { 1399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mDurationMs = durationMs; 1409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung int32_t getId() const { 1439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mId; 1449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void setId(int32_t id) { 1479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mId = id; 1489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung T adjustVolume(T volume) const { 1519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if ((getOptionFlags() & OPTION_FLAG_VOLUME_IN_DBFS) != 0) { 1529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T out = powf(10.f, volume / 10.); 1539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("in: %f out: %f", volume, out); 1549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung volume = out; 1559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // clamp 1579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (volume < 0.f) { 1589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung volume = 0.f; 1599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else if (volume > 1.f) { 1609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung volume = 1.f; 1619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return volume; 1639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t checkCurve() { 1669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (mType == TYPE_ID) return NO_ERROR; 1679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (this->size() < 2) { 1689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("curve must have at least 2 points"); 1699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return BAD_VALUE; 1709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (first().first != 0.f || last().first != 1.f) { 1729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("curve must start at 0.f and end at 1.f"); 1739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return BAD_VALUE; 1749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if ((getOptionFlags() & OPTION_FLAG_VOLUME_IN_DBFS) != 0) { 1769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (const auto &pt : *this) { 1779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (!(pt.second <= 0.f) /* handle nan */) { 1789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("positive volume dbFS"); 1799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return BAD_VALUE; 1809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else { 1839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (const auto &pt : *this) { 1849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (!(pt.second >= 0.f) || !(pt.second <= 1.f) /* handle nan */) { 1859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("volume < 0.f or > 1.f"); 1869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return BAD_VALUE; 1879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return NO_ERROR; 1919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void clampVolume() { 1949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if ((mOptionFlags & OPTION_FLAG_VOLUME_IN_DBFS) != 0) { 1959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (auto it = this->begin(); it != this->end(); ++it) { 1969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (!(it->second <= 0.f) /* handle nan */) { 1979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung it->second = 0.f; 1989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else { 2019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (auto it = this->begin(); it != this->end(); ++it) { 2029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (!(it->second >= 0.f) /* handle nan */) { 2039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung it->second = 0.f; 2049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else if (!(it->second <= 1.f)) { 2059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung it->second = 1.f; 2069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung /* scaleToStartVolume() is used to set the start volume of a 2129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * new VolumeShaper curve, when replacing one VolumeShaper 2139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * with another using the "join" (volume match) option. 2149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * 2159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * It works best for monotonic volume ramps or ducks. 2169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung */ 2179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void scaleToStartVolume(T volume) { 2189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (this->size() < 2) { 2199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return; 2209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T startVolume = first().second; 2229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T endVolume = last().second; 2239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (endVolume == startVolume) { 2249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // match with linear ramp 2259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T offset = volume - startVolume; 2269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (auto it = this->begin(); it != this->end(); ++it) { 2279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung it->second = it->second + offset * (1.f - it->first); 2289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else { 2309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T scale = (volume - endVolume) / (startVolume - endVolume); 2319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (auto it = this->begin(); it != this->end(); ++it) { 2329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung it->second = scale * (it->second - endVolume) + endVolume; 2339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung clampVolume(); 2369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t writeToParcel(Parcel *parcel) const { 2399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (parcel == nullptr) return BAD_VALUE; 2409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return parcel->writeInt32((int32_t)mType) 2419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: parcel->writeInt32(mId) 2429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: mType == TYPE_ID 2439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ? NO_ERROR 2449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : parcel->writeInt32((int32_t)mOptionFlags) 2459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: parcel->writeDouble(mDurationMs) 2469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: Interpolator<S, T>::writeToParcel(parcel); 2479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t readFromParcel(const Parcel &parcel) { 2509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung int32_t type, optionFlags; 2519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return parcel.readInt32(&type) 2529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: setType((Type)type) 2539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: parcel.readInt32(&mId) 2549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: mType == TYPE_ID 2559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ? NO_ERROR 2569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : parcel.readInt32(&optionFlags) 2579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: setOptionFlags((OptionFlag)optionFlags) 2589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: parcel.readDouble(&mDurationMs) 2599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: Interpolator<S, T>::readFromParcel(parcel) 2609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: checkCurve(); 2619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::string toString() const { 2649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::stringstream ss; 2659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mType: " << mType << std::endl; 2669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mId: " << mId << std::endl; 2679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (mType != TYPE_ID) { 2689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mOptionFlags: " << mOptionFlags << std::endl; 2699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mDurationMs: " << mDurationMs << std::endl; 2709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << Interpolator<S, T>::toString().c_str(); 2719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return ss.str(); 2739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung private: 2769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Type mType; 2779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung int32_t mId; 2789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung OptionFlag mOptionFlags; 2799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung double mDurationMs; 2809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung }; // Configuration 2819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // must match with VolumeShaper.java in frameworks/base 2839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // TODO document per VolumeShaper.java flags. 2849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung class Operation : public RefBase { 2859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung public: 2869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung enum Flag : int32_t { 2879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung FLAG_NONE = 0, 2889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung FLAG_REVERSE = (1 << 0), 2899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung FLAG_TERMINATE = (1 << 1), 2909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung FLAG_JOIN = (1 << 2), 2919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung FLAG_DELAY = (1 << 3), 2929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung FLAG_ALL = (FLAG_REVERSE | FLAG_TERMINATE | FLAG_JOIN | FLAG_DELAY), 2949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung }; 2959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Operation() 2979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : mFlags(FLAG_NONE) 2989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mReplaceId(-1) { 2999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung explicit Operation(Flag flags, int replaceId) 3029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : mFlags(flags) 3039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mReplaceId(replaceId) { 3049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung int32_t getReplaceId() const { 3079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mReplaceId; 3089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void setReplaceId(int32_t replaceId) { 3119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mReplaceId = replaceId; 3129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Flag getFlags() const { 3159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mFlags; 3169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t setFlags(Flag flags) { 3199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if ((flags & ~FLAG_ALL) != 0) { 3209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("flags has invalid bits: %#x", flags); 3219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return BAD_VALUE; 3229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mFlags = flags; 3249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return NO_ERROR; 3259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t writeToParcel(Parcel *parcel) const { 3289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (parcel == nullptr) return BAD_VALUE; 3299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return parcel->writeInt32((int32_t)mFlags) 3309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: parcel->writeInt32(mReplaceId); 3319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t readFromParcel(const Parcel &parcel) { 3349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung int32_t flags; 3359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return parcel.readInt32(&flags) 3369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: parcel.readInt32(&mReplaceId) 3379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: setFlags((Flag)flags); 3389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::string toString() const { 3419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::stringstream ss; 3429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mFlags: " << mFlags << std::endl; 3439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mReplaceId: " << mReplaceId << std::endl; 3449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return ss.str(); 3459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung private: 3489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Flag mFlags; 3499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung int32_t mReplaceId; 3509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung }; // Operation 3519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // must match with VolumeShaper.java in frameworks/base 3539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung class State : public RefBase { 3549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung public: 3559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung explicit State(T volume, S xOffset) 3569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : mVolume(volume) 3579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mXOffset(xOffset) { 3589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung State() 3619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : State(-1.f, -1.f) { } 3629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung T getVolume() const { 3649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mVolume; 3659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void setVolume(T volume) { 3689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mVolume = volume; 3699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung S getXOffset() const { 3729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mXOffset; 3739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void setXOffset(S xOffset) { 3769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mXOffset = xOffset; 3779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t writeToParcel(Parcel *parcel) const { 3809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (parcel == nullptr) return BAD_VALUE; 3819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return parcel->writeFloat(mVolume) 3829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: parcel->writeFloat(mXOffset); 3839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t readFromParcel(const Parcel &parcel) { 3869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return parcel.readFloat(&mVolume) 3879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: parcel.readFloat(&mXOffset); 3889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::string toString() const { 3919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::stringstream ss; 3929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mVolume: " << mVolume << std::endl; 3939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mXOffset: " << mXOffset << std::endl; 3949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return ss.str(); 3959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung private: 3989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung T mVolume; 3999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung S mXOffset; 4009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung }; // State 4019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung template <typename R> 4039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung class Translate { 4049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung public: 4059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Translate() 4069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : mOffset(0) 4079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mScale(1) { 4089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung R getOffset() const { 4119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mOffset; 4129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void setOffset(R offset) { 4159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mOffset = offset; 4169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung R getScale() const { 4199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mScale; 4209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void setScale(R scale) { 4239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mScale = scale; 4249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung R operator()(R in) const { 4279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mScale * (in - mOffset); 4289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::string toString() const { 4319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::stringstream ss; 4329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mOffset: " << mOffset << std::endl; 4339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mScale: " << mScale << std::endl; 4349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return ss.str(); 4359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung private: 4389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung R mOffset; 4399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung R mScale; 4409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung }; // Translate 4419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung static int64_t convertTimespecToUs(const struct timespec &tv) 4439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung { 4449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return tv.tv_sec * 1000000ll + tv.tv_nsec / 1000; 4459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // current monotonic time in microseconds. 4489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung static int64_t getNowUs() 4499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung { 4509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung struct timespec tv; 4519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (clock_gettime(CLOCK_MONOTONIC, &tv) != 0) { 4529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return 0; // system is really sick, just return 0 for consistency. 4539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return convertTimespecToUs(tv); 4559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Translate<S> mXTranslate; 4589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Translate<T> mYTranslate; 4599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung sp<VolumeShaper::Configuration> mConfiguration; 4609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung sp<VolumeShaper::Operation> mOperation; 4619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung int64_t mStartFrame; 4629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung T mLastVolume; 4639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung S mXOffset; 4649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // TODO: Since we pass configuration and operation as shared pointers 4669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // there is a potential risk that the caller may modify these after 4679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // delivery. Currently, we don't require copies made here. 4689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung explicit VolumeShaper( 4699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const sp<VolumeShaper::Configuration> &configuration, 4709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const sp<VolumeShaper::Operation> &operation) 4719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : mConfiguration(configuration) // we do not make a copy 4729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mOperation(operation) // ditto 4739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mStartFrame(-1) 4749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mLastVolume(T(1)) 4759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mXOffset(0.f) { 4769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (configuration.get() != nullptr 4779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung && (getFlags() & VolumeShaper::Operation::FLAG_DELAY) == 0) { 4789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastVolume = configuration->first().second; 4799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void updatePosition(int64_t startFrame, double sampleRate) { 4839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung double scale = (mConfiguration->last().first - mConfiguration->first().first) 4849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung / (mConfiguration->getDurationMs() * 0.001 * sampleRate); 4859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const double minScale = 1. / INT64_MAX; 4869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung scale = std::max(scale, minScale); 4879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("update position: scale %lf frameCount:%lld, sampleRate:%lf", 4889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung scale, (long long) startFrame, sampleRate); 4899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mXTranslate.setOffset(startFrame - mConfiguration->first().first / scale); 4909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mXTranslate.setScale(scale); 4919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("translate: %s", mXTranslate.toString().c_str()); 4929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // We allow a null operation here, though VolumeHandler always provides one. 4959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VolumeShaper::Operation::Flag getFlags() const { 4969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mOperation == nullptr 4979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ? VolumeShaper::Operation::FLAG_NONE :mOperation->getFlags(); 4989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 5009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung sp<VolumeShaper::State> getState() const { 5019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return new VolumeShaper::State(mLastVolume, mXOffset); 5029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 50410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung std::pair<T /* volume */, bool /* active */> getVolume( 50510cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung int64_t trackFrameCount, double trackSampleRate) { 5069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if ((getFlags() & VolumeShaper::Operation::FLAG_DELAY) != 0) { 5079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("delayed VolumeShaper, ignoring"); 5089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastVolume = T(1); 5099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mXOffset = 0.; 5109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return std::make_pair(T(1), false); 5119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const bool clockTime = (mConfiguration->getOptionFlags() 5139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung & VolumeShaper::Configuration::OPTION_FLAG_CLOCK_TIME) != 0; 5149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const int64_t frameCount = clockTime ? getNowUs() : trackFrameCount; 5159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const double sampleRate = clockTime ? 1000000 : trackSampleRate; 5169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 5179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (mStartFrame < 0) { 5189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung updatePosition(frameCount, sampleRate); 5199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mStartFrame = frameCount; 5209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("frameCount: %lld", (long long)frameCount); 5229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung S x = mXTranslate((T)frameCount); 5239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("translation: %f", x); 5249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 5259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // handle reversal of position 5269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (getFlags() & VolumeShaper::Operation::FLAG_REVERSE) { 5279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung x = 1.f - x; 5289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("reversing to %f", x); 5299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (x < mConfiguration->first().first) { 5309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mXOffset = 1.f; 5319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T volume = mConfiguration->adjustVolume( 5329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mConfiguration->first().second); // persist last value 5339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("persisting volume %f", volume); 5349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastVolume = volume; 5359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return std::make_pair(volume, false); 5369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (x > mConfiguration->last().first) { 5389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mXOffset = 0.f; 5399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastVolume = 1.f; 54010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung return std::make_pair(T(1), true); // too early 5419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else { 5439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (x < mConfiguration->first().first) { 5449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mXOffset = 0.f; 5459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastVolume = 1.f; 54610cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung return std::make_pair(T(1), true); // too early 5479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (x > mConfiguration->last().first) { 5499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mXOffset = 1.f; 5509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T volume = mConfiguration->adjustVolume( 5519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mConfiguration->last().second); // persist last value 5529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("persisting volume %f", volume); 5539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastVolume = volume; 5549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return std::make_pair(volume, false); 5559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mXOffset = x; 5589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // x contains the location on the volume curve to use. 5599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T unscaledVolume = mConfiguration->findY(x); 5609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T volumeChange = mYTranslate(unscaledVolume); 5619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T volume = mConfiguration->adjustVolume(volumeChange); 5629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("volume: %f unscaled: %f", volume, unscaledVolume); 5639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastVolume = volume; 56410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung return std::make_pair(volume, true); 5659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 5679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::string toString() const { 5689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::stringstream ss; 5699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "StartFrame: " << mStartFrame << std::endl; 5709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << mXTranslate.toString().c_str(); 5719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << mYTranslate.toString().c_str(); 5729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (mConfiguration.get() == nullptr) { 5739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "VolumeShaper::Configuration: nullptr" << std::endl; 5749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else { 5759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "VolumeShaper::Configuration:" << std::endl; 5769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << mConfiguration->toString().c_str(); 5779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (mOperation.get() == nullptr) { 5799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "VolumeShaper::Operation: nullptr" << std::endl; 5809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else { 5819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "VolumeShaper::Operation:" << std::endl; 5829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << mOperation->toString().c_str(); 5839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return ss.str(); 5859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung}; // VolumeShaper 5879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 5889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// VolumeHandler combines the volume factors of multiple VolumeShapers and handles 5899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// multiple thread access by synchronizing all public methods. 5909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungclass VolumeHandler : public RefBase { 5919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungpublic: 5929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung using S = float; 5939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung using T = float; 5949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 5959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung explicit VolumeHandler(uint32_t sampleRate) 5969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : mSampleRate((double)sampleRate) 5979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mLastFrame(0) { 5989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 6009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VolumeShaper::Status applyVolumeShaper( 6019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const sp<VolumeShaper::Configuration> &configuration, 6029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const sp<VolumeShaper::Operation> &operation) { 60310cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung VS_LOG("applyVolumeShaper:configuration: %s", configuration->toString().c_str()); 60410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung VS_LOG("applyVolumeShaper:operation: %s", operation->toString().c_str()); 6059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung AutoMutex _l(mLock); 6069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (configuration == nullptr) { 6079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("null configuration"); 6089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return VolumeShaper::Status(BAD_VALUE); 6099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (operation == nullptr) { 6119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("null operation"); 6129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return VolumeShaper::Status(BAD_VALUE); 6139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const int32_t id = configuration->getId(); 6159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (id < 0) { 6169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("negative id: %d", id); 6179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return VolumeShaper::Status(BAD_VALUE); 6189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("applyVolumeShaper id: %d", id); 6209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 6219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung switch (configuration->getType()) { 6229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung case VolumeShaper::Configuration::TYPE_SCALE: { 6239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const int replaceId = operation->getReplaceId(); 6249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (replaceId >= 0) { 6259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung auto replaceIt = findId_l(replaceId); 6269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (replaceIt == mVolumeShapers.end()) { 6279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGW("cannot find replace id: %d", replaceId); 6289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else { 6299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if ((replaceIt->getFlags() & VolumeShaper::Operation::FLAG_JOIN) != 0) { 6309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // For join, we scale the start volume of the current configuration 6319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // to match the last-used volume of the replacing VolumeShaper. 6329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung auto state = replaceIt->getState(); 6339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (state->getXOffset() >= 0) { // valid 6349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T volume = state->getVolume(); 6359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGD("join: scaling start volume to %f", volume); 6369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung configuration->scaleToStartVolume(volume); 6379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung (void)mVolumeShapers.erase(replaceIt); 6409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // check if we have another of the same id. 6439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung auto oldIt = findId_l(id); 6449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (oldIt != mVolumeShapers.end()) { 6459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGW("duplicate id, removing old %d", id); 6469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung (void)mVolumeShapers.erase(oldIt); 6479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // create new VolumeShaper 6499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mVolumeShapers.emplace_back(configuration, operation); 65010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung } 65110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung // fall through to handle the operation 65210cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung case VolumeShaper::Configuration::TYPE_ID: { 65310cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung VS_LOG("trying to find id: %d", id); 65410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung auto it = findId_l(id); 65510cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung if (it == mVolumeShapers.end()) { 65610cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung VS_LOG("couldn't find id: %d", id); 65710cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung return VolumeShaper::Status(INVALID_OPERATION); 65810cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung } 65910cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung if ((it->getFlags() & VolumeShaper::Operation::FLAG_TERMINATE) != 0) { 66010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung VS_LOG("terminate id: %d", id); 66110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung mVolumeShapers.erase(it); 66210cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung break; 66310cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung } 66410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung const bool clockTime = (it->mConfiguration->getOptionFlags() 66510cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung & VolumeShaper::Configuration::OPTION_FLAG_CLOCK_TIME) != 0; 66610cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung if ((it->getFlags() & VolumeShaper::Operation::FLAG_REVERSE) != 66710cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung (operation->getFlags() & VolumeShaper::Operation::FLAG_REVERSE)) { 66810cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung const int64_t frameCount = clockTime ? VolumeShaper::getNowUs() : mLastFrame; 66910cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung const S x = it->mXTranslate((T)frameCount); 67010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung VS_LOG("reverse translation: %f", x); 67110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung // reflect position 67210cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung S target = 1.f - x; 67310cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung if (target < it->mConfiguration->first().first) { 67410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung VS_LOG("clamp to start - begin immediately"); 67510cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung target = 0.; 67610cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung } 67710cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung VS_LOG("target reverse: %f", target); 67810cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung it->mXTranslate.setOffset(it->mXTranslate.getOffset() 67910cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung + (x - target) / it->mXTranslate.getScale()); 68010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung } 68110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung it->mOperation = operation; // replace the operation 6829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } break; 6839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return VolumeShaper::Status(id); 6859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 6879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung sp<VolumeShaper::State> getVolumeShaperState(int id) { 6889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung AutoMutex _l(mLock); 6899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung auto it = findId_l(id); 6909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (it == mVolumeShapers.end()) { 6919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return nullptr; 6929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return it->getState(); 6949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 69610cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung std::pair<T /* volume */, bool /* active */> getVolume(int64_t trackFrameCount) { 6979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung AutoMutex _l(mLock); 6989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastFrame = trackFrameCount; 6999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung T volume(1); 70010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung size_t activeCount = 0; 7019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (auto it = mVolumeShapers.begin(); it != mVolumeShapers.end();) { 7029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::pair<T, bool> shaperVolume = 7039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung it->getVolume(trackFrameCount, mSampleRate); 7049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung volume *= shaperVolume.first; 70510cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung activeCount += shaperVolume.second; 7069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ++it; 7079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 70810cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung return std::make_pair(volume, activeCount != 0); 7099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 7109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 7119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::string toString() const { 7129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung AutoMutex _l(mLock); 7139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::stringstream ss; 7149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mSampleRate: " << mSampleRate << std::endl; 7159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mLastFrame: " << mLastFrame << std::endl; 7169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (const auto &shaper : mVolumeShapers) { 7179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << shaper.toString().c_str(); 7189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 7199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return ss.str(); 7209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 7219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 7229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungprivate: 7239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::list<VolumeShaper>::iterator findId_l(int32_t id) { 7249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::list<VolumeShaper>::iterator it = mVolumeShapers.begin(); 7259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (; it != mVolumeShapers.end(); ++it) { 7269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (it->mConfiguration->getId() == id) { 7279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung break; 7289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 7299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 7309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return it; 7319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 7329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 7339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mutable Mutex mLock; 7349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung double mSampleRate; // in samples (frames) per second 7359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung int64_t mLastFrame; // logging purpose only 7369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::list<VolumeShaper> mVolumeShapers; // list provides stable iterators on erase 7379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung}; // VolumeHandler 7389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 7399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung} // namespace android 7409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 7419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#pragma pop_macro("LOG_TAG") 7429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 7439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#endif // ANDROID_VOLUME_SHAPER_H 744