VolumeShaper.h revision 39399b6b08b4e9fd7eae50e58e93b07216ad697f
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 204ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung#include <cmath> 219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <list> 229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <math.h> 239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <sstream> 249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <binder/Parcel.h> 269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <media/Interpolator.h> 279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <utils/Mutex.h> 289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#include <utils/RefBase.h> 299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#pragma push_macro("LOG_TAG") 319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#undef LOG_TAG 329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#define LOG_TAG "VolumeShaper" 339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// turn on VolumeShaper logging 359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#if 0 369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#define VS_LOG ALOGD 379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#else 389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#define VS_LOG(...) 399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#endif 409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungnamespace android { 429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// The native VolumeShaper class mirrors the java VolumeShaper class; 449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// in addition, the native class contains implementation for actual operation. 459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// 469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// VolumeShaper methods are not safe for multiple thread access. 479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// Use VolumeHandler for thread-safe encapsulation of multiple VolumeShapers. 489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// 499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// Classes below written are to avoid naked pointers so there are no 509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// explicit destructors required. 519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungclass VolumeShaper { 539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungpublic: 549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung using S = float; 559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung using T = float; 569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung static const int kSystemIdMax = 16; 589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // VolumeShaper::Status is equivalent to status_t if negative 609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // but if non-negative represents the id operated on. 619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // It must be expressible as an int32_t for binder purposes. 629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung using Status = status_t; 639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung class Configuration : public Interpolator<S, T>, public RefBase { 659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung public: 669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung /* VolumeShaper.Configuration derives from the Interpolator class and adds 679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * parameters relating to the volume shape. 689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung */ 699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // TODO document as per VolumeShaper.java flags. 719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // must match with VolumeShaper.java in frameworks/base 739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung enum Type : int32_t { 749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung TYPE_ID, 759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung TYPE_SCALE, 769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung }; 779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // must match with VolumeShaper.java in frameworks/base 799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung enum OptionFlag : int32_t { 809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung OPTION_FLAG_NONE = 0, 819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung OPTION_FLAG_VOLUME_IN_DBFS = (1 << 0), 829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung OPTION_FLAG_CLOCK_TIME = (1 << 1), 839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung OPTION_FLAG_ALL = (OPTION_FLAG_VOLUME_IN_DBFS | OPTION_FLAG_CLOCK_TIME), 859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung }; 869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // bring to derived class; must match with VolumeShaper.java in frameworks/base 889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung using InterpolatorType = Interpolator<S, T>::InterpolatorType; 899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Configuration() 919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : Interpolator<S, T>() 929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mType(TYPE_SCALE) 939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mOptionFlags(OPTION_FLAG_NONE) 949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mDurationMs(1000.) 959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mId(-1) { 969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 987d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung explicit Configuration(const Configuration &configuration) 9910cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung : Interpolator<S, T>(*static_cast<const Interpolator<S, T> *>(&configuration)) 10010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung , mType(configuration.mType) 10110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung , mOptionFlags(configuration.mOptionFlags) 10210cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung , mDurationMs(configuration.mDurationMs) 10310cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung , mId(configuration.mId) { 10410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung } 10510cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung 1069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Type getType() const { 1079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mType; 1089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t setType(Type type) { 1119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung switch (type) { 1129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung case TYPE_ID: 1139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung case TYPE_SCALE: 1149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mType = type; 1159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return NO_ERROR; 1169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung default: 1179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("invalid Type: %d", type); 1189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return BAD_VALUE; 1199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung OptionFlag getOptionFlags() const { 1239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mOptionFlags; 1249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t setOptionFlags(OptionFlag optionFlags) { 1279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if ((optionFlags & ~OPTION_FLAG_ALL) != 0) { 1289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("optionFlags has invalid bits: %#x", optionFlags); 1299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return BAD_VALUE; 1309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mOptionFlags = optionFlags; 1329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return NO_ERROR; 1339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung double getDurationMs() const { 1369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mDurationMs; 1379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void setDurationMs(double durationMs) { 1409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mDurationMs = durationMs; 1419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung int32_t getId() const { 1449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mId; 1459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void setId(int32_t id) { 1489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mId = id; 1499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung T adjustVolume(T volume) const { 1529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if ((getOptionFlags() & OPTION_FLAG_VOLUME_IN_DBFS) != 0) { 1539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T out = powf(10.f, volume / 10.); 1549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("in: %f out: %f", volume, out); 1559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung volume = out; 1569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // clamp 1589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (volume < 0.f) { 1599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung volume = 0.f; 1609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else if (volume > 1.f) { 1619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung volume = 1.f; 1629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return volume; 1649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t checkCurve() { 1679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (mType == TYPE_ID) return NO_ERROR; 1689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (this->size() < 2) { 1699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("curve must have at least 2 points"); 1709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return BAD_VALUE; 1719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (first().first != 0.f || last().first != 1.f) { 1739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("curve must start at 0.f and end at 1.f"); 1749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return BAD_VALUE; 1759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if ((getOptionFlags() & OPTION_FLAG_VOLUME_IN_DBFS) != 0) { 1779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (const auto &pt : *this) { 1789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (!(pt.second <= 0.f) /* handle nan */) { 1799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("positive volume dbFS"); 1809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return BAD_VALUE; 1819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else { 1849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (const auto &pt : *this) { 1859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (!(pt.second >= 0.f) || !(pt.second <= 1.f) /* handle nan */) { 1869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("volume < 0.f or > 1.f"); 1879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return BAD_VALUE; 1889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return NO_ERROR; 1929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void clampVolume() { 1959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if ((mOptionFlags & OPTION_FLAG_VOLUME_IN_DBFS) != 0) { 1969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (auto it = this->begin(); it != this->end(); ++it) { 1979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (!(it->second <= 0.f) /* handle nan */) { 1989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung it->second = 0.f; 1999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else { 2029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (auto it = this->begin(); it != this->end(); ++it) { 2039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (!(it->second >= 0.f) /* handle nan */) { 2049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung it->second = 0.f; 2059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else if (!(it->second <= 1.f)) { 2069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung it->second = 1.f; 2079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung /* scaleToStartVolume() is used to set the start volume of a 2139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * new VolumeShaper curve, when replacing one VolumeShaper 2149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * with another using the "join" (volume match) option. 2159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * 2169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * It works best for monotonic volume ramps or ducks. 2179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung */ 2189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void scaleToStartVolume(T volume) { 2199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (this->size() < 2) { 2209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return; 2219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T startVolume = first().second; 2239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T endVolume = last().second; 2249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (endVolume == startVolume) { 2259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // match with linear ramp 2269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T offset = volume - startVolume; 2279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (auto it = this->begin(); it != this->end(); ++it) { 2289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung it->second = it->second + offset * (1.f - it->first); 2299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else { 2319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T scale = (volume - endVolume) / (startVolume - endVolume); 2329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (auto it = this->begin(); it != this->end(); ++it) { 2339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung it->second = scale * (it->second - endVolume) + endVolume; 2349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung clampVolume(); 2379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2397d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung // The parcel layout must match VolumeShaper.java 2409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t writeToParcel(Parcel *parcel) const { 2419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (parcel == nullptr) return BAD_VALUE; 2429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return parcel->writeInt32((int32_t)mType) 2439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: parcel->writeInt32(mId) 2449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: mType == TYPE_ID 2459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ? NO_ERROR 2469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : parcel->writeInt32((int32_t)mOptionFlags) 2479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: parcel->writeDouble(mDurationMs) 2489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: Interpolator<S, T>::writeToParcel(parcel); 2499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t readFromParcel(const Parcel &parcel) { 2529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung int32_t type, optionFlags; 2539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return parcel.readInt32(&type) 2549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: setType((Type)type) 2559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: parcel.readInt32(&mId) 2569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: mType == TYPE_ID 2579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ? NO_ERROR 2589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : parcel.readInt32(&optionFlags) 2599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: setOptionFlags((OptionFlag)optionFlags) 2609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: parcel.readDouble(&mDurationMs) 2619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: Interpolator<S, T>::readFromParcel(parcel) 2629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: checkCurve(); 2639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::string toString() const { 2669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::stringstream ss; 2679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mType: " << mType << std::endl; 2689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mId: " << mId << std::endl; 2699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (mType != TYPE_ID) { 2709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mOptionFlags: " << mOptionFlags << std::endl; 2719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mDurationMs: " << mDurationMs << std::endl; 2729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << Interpolator<S, T>::toString().c_str(); 2739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return ss.str(); 2759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung private: 2789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Type mType; 2799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung int32_t mId; 2809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung OptionFlag mOptionFlags; 2819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung double mDurationMs; 2829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung }; // Configuration 2839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // must match with VolumeShaper.java in frameworks/base 2859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // TODO document per VolumeShaper.java flags. 2869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung class Operation : public RefBase { 2879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung public: 2889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung enum Flag : int32_t { 2899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung FLAG_NONE = 0, 2909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung FLAG_REVERSE = (1 << 0), 2919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung FLAG_TERMINATE = (1 << 1), 2929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung FLAG_JOIN = (1 << 2), 2939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung FLAG_DELAY = (1 << 3), 2944ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung FLAG_CREATE_IF_NECESSARY = (1 << 4), 2959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2964ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung FLAG_ALL = (FLAG_REVERSE | FLAG_TERMINATE | FLAG_JOIN | FLAG_DELAY 2974ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung | FLAG_CREATE_IF_NECESSARY), 2989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung }; 2999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Operation() 3014ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung : Operation(FLAG_NONE, -1 /* replaceId */) { 3029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3047d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung Operation(Flag flags, int replaceId) 3054ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung : Operation(flags, replaceId, std::numeric_limits<S>::quiet_NaN() /* xOffset */) { 3064ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung } 3074ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung 3087d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung explicit Operation(const Operation &operation) 3094ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung : Operation(operation.mFlags, operation.mReplaceId, operation.mXOffset) { 3104ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung } 3114ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung 3127d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung explicit Operation(const sp<Operation> &operation) 3137d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung : Operation(*operation.get()) { 3147d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung } 3157d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung 3167d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung Operation(Flag flags, int replaceId, S xOffset) 3179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : mFlags(flags) 3184ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung , mReplaceId(replaceId) 3194ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung , mXOffset(xOffset) { 3209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung int32_t getReplaceId() const { 3239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mReplaceId; 3249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void setReplaceId(int32_t replaceId) { 3279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mReplaceId = replaceId; 3289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3304ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung S getXOffset() const { 3314ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung return mXOffset; 3324ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung } 3334ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung 3344ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung void setXOffset(S xOffset) { 3354ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung mXOffset = xOffset; 3364ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung } 3374ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung 3389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Flag getFlags() const { 3399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mFlags; 3409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t setFlags(Flag flags) { 3439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if ((flags & ~FLAG_ALL) != 0) { 3449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("flags has invalid bits: %#x", flags); 3459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return BAD_VALUE; 3469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mFlags = flags; 3489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return NO_ERROR; 3499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t writeToParcel(Parcel *parcel) const { 3529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (parcel == nullptr) return BAD_VALUE; 3539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return parcel->writeInt32((int32_t)mFlags) 3544ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung ?: parcel->writeInt32(mReplaceId) 3554ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung ?: parcel->writeFloat(mXOffset); 3569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t readFromParcel(const Parcel &parcel) { 3599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung int32_t flags; 3609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return parcel.readInt32(&flags) 3619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: parcel.readInt32(&mReplaceId) 3624ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung ?: parcel.readFloat(&mXOffset) 3639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: setFlags((Flag)flags); 3649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::string toString() const { 3679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::stringstream ss; 3689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mFlags: " << mFlags << std::endl; 3699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mReplaceId: " << mReplaceId << std::endl; 3704ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung ss << "mXOffset: " << mXOffset << std::endl; 3719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return ss.str(); 3729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung private: 3759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Flag mFlags; 3769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung int32_t mReplaceId; 3774ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung S mXOffset; 3789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung }; // Operation 3799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // must match with VolumeShaper.java in frameworks/base 3819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung class State : public RefBase { 3829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung public: 3837d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung State(T volume, S xOffset) 3849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : mVolume(volume) 3859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mXOffset(xOffset) { 3869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung State() 3899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : State(-1.f, -1.f) { } 3909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung T getVolume() const { 3929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mVolume; 3939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void setVolume(T volume) { 3969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mVolume = volume; 3979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung S getXOffset() const { 4009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mXOffset; 4019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void setXOffset(S xOffset) { 4049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mXOffset = xOffset; 4059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t writeToParcel(Parcel *parcel) const { 4089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (parcel == nullptr) return BAD_VALUE; 4099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return parcel->writeFloat(mVolume) 4109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: parcel->writeFloat(mXOffset); 4119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t readFromParcel(const Parcel &parcel) { 4149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return parcel.readFloat(&mVolume) 4159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: parcel.readFloat(&mXOffset); 4169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::string toString() const { 4199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::stringstream ss; 4209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mVolume: " << mVolume << std::endl; 4219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mXOffset: " << mXOffset << std::endl; 4229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return ss.str(); 4239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung private: 4269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung T mVolume; 4279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung S mXOffset; 4289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung }; // State 4299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung template <typename R> 4319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung class Translate { 4329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung public: 4339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Translate() 4349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : mOffset(0) 4359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mScale(1) { 4369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung R getOffset() const { 4399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mOffset; 4409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void setOffset(R offset) { 4439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mOffset = offset; 4449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung R getScale() const { 4479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mScale; 4489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void setScale(R scale) { 4519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mScale = scale; 4529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung R operator()(R in) const { 4559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mScale * (in - mOffset); 4569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::string toString() const { 4599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::stringstream ss; 4609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mOffset: " << mOffset << std::endl; 4619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mScale: " << mScale << std::endl; 4629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return ss.str(); 4639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung private: 4669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung R mOffset; 4679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung R mScale; 4689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung }; // Translate 4699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung static int64_t convertTimespecToUs(const struct timespec &tv) 4719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung { 4729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return tv.tv_sec * 1000000ll + tv.tv_nsec / 1000; 4739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // current monotonic time in microseconds. 4769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung static int64_t getNowUs() 4779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung { 4789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung struct timespec tv; 4799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (clock_gettime(CLOCK_MONOTONIC, &tv) != 0) { 4809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return 0; // system is really sick, just return 0 for consistency. 4819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return convertTimespecToUs(tv); 4839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // TODO: Since we pass configuration and operation as shared pointers 4869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // there is a potential risk that the caller may modify these after 4879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // delivery. Currently, we don't require copies made here. 4887d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung VolumeShaper( 4899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const sp<VolumeShaper::Configuration> &configuration, 4909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const sp<VolumeShaper::Operation> &operation) 4919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : mConfiguration(configuration) // we do not make a copy 4929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mOperation(operation) // ditto 4939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mStartFrame(-1) 4949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mLastVolume(T(1)) 4954ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung , mLastXOffset(0.f) 4964ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung , mDelayXOffset(std::numeric_limits<S>::quiet_NaN()) { 4979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (configuration.get() != nullptr 4989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung && (getFlags() & VolumeShaper::Operation::FLAG_DELAY) == 0) { 4999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastVolume = configuration->first().second; 5009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 5039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void updatePosition(int64_t startFrame, double sampleRate) { 5049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung double scale = (mConfiguration->last().first - mConfiguration->first().first) 5059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung / (mConfiguration->getDurationMs() * 0.001 * sampleRate); 5069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const double minScale = 1. / INT64_MAX; 5079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung scale = std::max(scale, minScale); 5084ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung const S xOffset = std::isnan(mDelayXOffset) ? mConfiguration->first().first : mDelayXOffset; 5094ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung VS_LOG("update position: scale %lf frameCount:%lld, sampleRate:%lf, xOffset:%f", 5104ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung scale, (long long) startFrame, sampleRate, xOffset); 5114ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung 5124ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung mXTranslate.setOffset(startFrame - xOffset / scale); 5139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mXTranslate.setScale(scale); 5149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("translate: %s", mXTranslate.toString().c_str()); 5159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 5179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // We allow a null operation here, though VolumeHandler always provides one. 5189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VolumeShaper::Operation::Flag getFlags() const { 5199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mOperation == nullptr 5209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ? VolumeShaper::Operation::FLAG_NONE :mOperation->getFlags(); 5219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 5239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung sp<VolumeShaper::State> getState() const { 5244ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung return new VolumeShaper::State(mLastVolume, mLastXOffset); 5254ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung } 5264ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung 5274ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung void setDelayXOffset(S xOffset) { 5284ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung mDelayXOffset = xOffset; 5299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 53139399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung bool isStarted() const { 53239399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung return mStartFrame >= 0; 53339399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung } 53439399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung 53510cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung std::pair<T /* volume */, bool /* active */> getVolume( 53610cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung int64_t trackFrameCount, double trackSampleRate) { 5379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if ((getFlags() & VolumeShaper::Operation::FLAG_DELAY) != 0) { 5389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("delayed VolumeShaper, ignoring"); 5399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastVolume = T(1); 5404ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung mLastXOffset = 0.; 5419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return std::make_pair(T(1), false); 5429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const bool clockTime = (mConfiguration->getOptionFlags() 5449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung & VolumeShaper::Configuration::OPTION_FLAG_CLOCK_TIME) != 0; 5459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const int64_t frameCount = clockTime ? getNowUs() : trackFrameCount; 5469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const double sampleRate = clockTime ? 1000000 : trackSampleRate; 5479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 5489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (mStartFrame < 0) { 5499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung updatePosition(frameCount, sampleRate); 5509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mStartFrame = frameCount; 5519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("frameCount: %lld", (long long)frameCount); 5539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung S x = mXTranslate((T)frameCount); 5549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("translation: %f", x); 5559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 5569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // handle reversal of position 5579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (getFlags() & VolumeShaper::Operation::FLAG_REVERSE) { 5589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung x = 1.f - x; 5599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("reversing to %f", x); 5609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (x < mConfiguration->first().first) { 5614ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung mLastXOffset = 1.f; 5629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T volume = mConfiguration->adjustVolume( 5639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mConfiguration->first().second); // persist last value 5649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("persisting volume %f", volume); 5659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastVolume = volume; 5669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return std::make_pair(volume, false); 5679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (x > mConfiguration->last().first) { 5694ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung mLastXOffset = 0.f; 5709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastVolume = 1.f; 57110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung return std::make_pair(T(1), true); // too early 5729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else { 5749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (x < mConfiguration->first().first) { 5754ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung mLastXOffset = 0.f; 5769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastVolume = 1.f; 57710cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung return std::make_pair(T(1), true); // too early 5789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (x > mConfiguration->last().first) { 5804ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung mLastXOffset = 1.f; 5819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T volume = mConfiguration->adjustVolume( 5829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mConfiguration->last().second); // persist last value 5839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("persisting volume %f", volume); 5849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastVolume = volume; 5859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return std::make_pair(volume, false); 5869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5884ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung mLastXOffset = x; 5899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // x contains the location on the volume curve to use. 5909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T unscaledVolume = mConfiguration->findY(x); 5914ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung const T volume = mConfiguration->adjustVolume(unscaledVolume); // handle log scale 5929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("volume: %f unscaled: %f", volume, unscaledVolume); 5939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastVolume = volume; 59410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung return std::make_pair(volume, true); 5959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 5979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::string toString() const { 5989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::stringstream ss; 5999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "StartFrame: " << mStartFrame << std::endl; 6009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << mXTranslate.toString().c_str(); 6019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (mConfiguration.get() == nullptr) { 6029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "VolumeShaper::Configuration: nullptr" << std::endl; 6039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else { 6049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "VolumeShaper::Configuration:" << std::endl; 6059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << mConfiguration->toString().c_str(); 6069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (mOperation.get() == nullptr) { 6089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "VolumeShaper::Operation: nullptr" << std::endl; 6099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else { 6109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "VolumeShaper::Operation:" << std::endl; 6119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << mOperation->toString().c_str(); 6129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return ss.str(); 6149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6154ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung 6164ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung Translate<S> mXTranslate; // x axis translation from frames (in usec for clock time) 6174ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung sp<VolumeShaper::Configuration> mConfiguration; 6184ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung sp<VolumeShaper::Operation> mOperation; 6194ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung int64_t mStartFrame; // starting frame, non-negative when started (in usec for clock time) 6204ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung T mLastVolume; // last computed interpolated volume (y-axis) 6214ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung S mLastXOffset; // last computed interpolated xOffset/time (x-axis) 6224ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung S mDelayXOffset; // delay xOffset on first volumeshaper start. 6239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung}; // VolumeShaper 6249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 6259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// VolumeHandler combines the volume factors of multiple VolumeShapers and handles 6269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// multiple thread access by synchronizing all public methods. 6279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungclass VolumeHandler : public RefBase { 6289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungpublic: 6299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung using S = float; 6309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung using T = float; 6319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 6324ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung // A volume handler which just keeps track of active VolumeShapers does not need sampleRate. 6334ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung VolumeHandler() 6344ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung : VolumeHandler(0 /* sampleRate */) { 6354ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung } 6364ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung 6379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung explicit VolumeHandler(uint32_t sampleRate) 6389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : mSampleRate((double)sampleRate) 6394ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung , mLastFrame(0) 640da540db0fc21bc9319d9602aefe1a109d00a7e6cAndy Hung , mVolumeShaperIdCounter(VolumeShaper::kSystemIdMax) 641da540db0fc21bc9319d9602aefe1a109d00a7e6cAndy Hung , mLastVolume(1.f, false) { 6429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 6449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VolumeShaper::Status applyVolumeShaper( 6459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const sp<VolumeShaper::Configuration> &configuration, 6469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const sp<VolumeShaper::Operation> &operation) { 64710cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung VS_LOG("applyVolumeShaper:configuration: %s", configuration->toString().c_str()); 64810cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung VS_LOG("applyVolumeShaper:operation: %s", operation->toString().c_str()); 6499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung AutoMutex _l(mLock); 6509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (configuration == nullptr) { 6519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("null configuration"); 6529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return VolumeShaper::Status(BAD_VALUE); 6539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (operation == nullptr) { 6559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("null operation"); 6569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return VolumeShaper::Status(BAD_VALUE); 6579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const int32_t id = configuration->getId(); 6599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (id < 0) { 6609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("negative id: %d", id); 6619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return VolumeShaper::Status(BAD_VALUE); 6629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("applyVolumeShaper id: %d", id); 6649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 6659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung switch (configuration->getType()) { 6669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung case VolumeShaper::Configuration::TYPE_SCALE: { 6679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const int replaceId = operation->getReplaceId(); 6689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (replaceId >= 0) { 6699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung auto replaceIt = findId_l(replaceId); 6709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (replaceIt == mVolumeShapers.end()) { 6719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGW("cannot find replace id: %d", replaceId); 6729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else { 6739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if ((replaceIt->getFlags() & VolumeShaper::Operation::FLAG_JOIN) != 0) { 6749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // For join, we scale the start volume of the current configuration 6759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // to match the last-used volume of the replacing VolumeShaper. 6769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung auto state = replaceIt->getState(); 6779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (state->getXOffset() >= 0) { // valid 6789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T volume = state->getVolume(); 6799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGD("join: scaling start volume to %f", volume); 6809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung configuration->scaleToStartVolume(volume); 6819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung (void)mVolumeShapers.erase(replaceIt); 6849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6854ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung operation->setReplaceId(-1); 6869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // check if we have another of the same id. 6889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung auto oldIt = findId_l(id); 6899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (oldIt != mVolumeShapers.end()) { 6904ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung if ((operation->getFlags() 6914ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung & VolumeShaper::Operation::FLAG_CREATE_IF_NECESSARY) != 0) { 6924ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung // TODO: move the case to a separate function. 6934ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung goto HANDLE_TYPE_ID; // no need to create, take over existing id. 6944ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung } 6959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGW("duplicate id, removing old %d", id); 6969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung (void)mVolumeShapers.erase(oldIt); 6979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // create new VolumeShaper 6999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mVolumeShapers.emplace_back(configuration, operation); 70010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung } 70110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung // fall through to handle the operation 7024ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung HANDLE_TYPE_ID: 70310cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung case VolumeShaper::Configuration::TYPE_ID: { 70410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung VS_LOG("trying to find id: %d", id); 70510cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung auto it = findId_l(id); 70610cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung if (it == mVolumeShapers.end()) { 70710cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung VS_LOG("couldn't find id: %d", id); 70810cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung return VolumeShaper::Status(INVALID_OPERATION); 70910cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung } 71010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung if ((it->getFlags() & VolumeShaper::Operation::FLAG_TERMINATE) != 0) { 71110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung VS_LOG("terminate id: %d", id); 71210cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung mVolumeShapers.erase(it); 71310cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung break; 71410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung } 71510cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung const bool clockTime = (it->mConfiguration->getOptionFlags() 71610cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung & VolumeShaper::Configuration::OPTION_FLAG_CLOCK_TIME) != 0; 71710cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung if ((it->getFlags() & VolumeShaper::Operation::FLAG_REVERSE) != 71810cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung (operation->getFlags() & VolumeShaper::Operation::FLAG_REVERSE)) { 71910cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung const int64_t frameCount = clockTime ? VolumeShaper::getNowUs() : mLastFrame; 72010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung const S x = it->mXTranslate((T)frameCount); 72110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung VS_LOG("reverse translation: %f", x); 72210cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung // reflect position 72310cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung S target = 1.f - x; 72410cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung if (target < it->mConfiguration->first().first) { 72510cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung VS_LOG("clamp to start - begin immediately"); 72610cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung target = 0.; 72710cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung } 72810cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung VS_LOG("target reverse: %f", target); 72910cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung it->mXTranslate.setOffset(it->mXTranslate.getOffset() 73010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung + (x - target) / it->mXTranslate.getScale()); 73110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung } 7324ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung const S xOffset = operation->getXOffset(); 7334ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung if (!std::isnan(xOffset)) { 7344ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung const int64_t frameCount = clockTime ? VolumeShaper::getNowUs() : mLastFrame; 7354ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung const S x = it->mXTranslate((T)frameCount); 7364ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung VS_LOG("xOffset translation: %f", x); 7374ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung const S target = xOffset; // offset 7384ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung VS_LOG("xOffset target x offset: %f", target); 7394ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung it->mXTranslate.setOffset(it->mXTranslate.getOffset() 7404ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung + (x - target) / it->mXTranslate.getScale()); 7414ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung it->setDelayXOffset(xOffset); 7424ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung } 74310cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung it->mOperation = operation; // replace the operation 7449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } break; 7459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 7469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return VolumeShaper::Status(id); 7479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 7489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 7499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung sp<VolumeShaper::State> getVolumeShaperState(int id) { 7509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung AutoMutex _l(mLock); 7519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung auto it = findId_l(id); 7529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (it == mVolumeShapers.end()) { 7534ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung VS_LOG("cannot find state for id: %d", id); 7549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return nullptr; 7559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 7569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return it->getState(); 7579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 7589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 75939399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung // getVolume() is not const, as it updates internal state. 76039399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung // Once called, any VolumeShapers not already started begin running. 76110cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung std::pair<T /* volume */, bool /* active */> getVolume(int64_t trackFrameCount) { 7629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung AutoMutex _l(mLock); 7639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastFrame = trackFrameCount; 7649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung T volume(1); 76510cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung size_t activeCount = 0; 7669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (auto it = mVolumeShapers.begin(); it != mVolumeShapers.end();) { 7679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::pair<T, bool> shaperVolume = 7689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung it->getVolume(trackFrameCount, mSampleRate); 7699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung volume *= shaperVolume.first; 77010cbff139360f3f642e0e3b3ccf2d463dbed22cfAndy Hung activeCount += shaperVolume.second; 7719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ++it; 7729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 773da540db0fc21bc9319d9602aefe1a109d00a7e6cAndy Hung mLastVolume = std::make_pair(volume, activeCount != 0); 774da540db0fc21bc9319d9602aefe1a109d00a7e6cAndy Hung return mLastVolume; 775da540db0fc21bc9319d9602aefe1a109d00a7e6cAndy Hung } 776da540db0fc21bc9319d9602aefe1a109d00a7e6cAndy Hung 77739399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung // Used by a client side VolumeHandler to ensure all the VolumeShapers 77839399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung // indicate that they have been started. Upon a change in audioserver 77939399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung // output sink, this information is used for restoration of the server side 78039399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung // VolumeHandler. 78139399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung void setStarted() { 78239399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung (void)getVolume(mLastFrame); // getVolume() will start the individual VolumeShapers. 78339399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung } 78439399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung 785da540db0fc21bc9319d9602aefe1a109d00a7e6cAndy Hung std::pair<T /* volume */, bool /* active */> getLastVolume() const { 786da540db0fc21bc9319d9602aefe1a109d00a7e6cAndy Hung AutoMutex _l(mLock); 787da540db0fc21bc9319d9602aefe1a109d00a7e6cAndy Hung return mLastVolume; 7889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 7899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 7909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::string toString() const { 7919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung AutoMutex _l(mLock); 7929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::stringstream ss; 7939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mSampleRate: " << mSampleRate << std::endl; 7949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mLastFrame: " << mLastFrame << std::endl; 7959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (const auto &shaper : mVolumeShapers) { 7969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << shaper.toString().c_str(); 7979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 7989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return ss.str(); 7999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 8009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 80139399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung void forall(const std::function<VolumeShaper::Status (const VolumeShaper &)> &lambda) { 8024ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung AutoMutex _l(mLock); 803da540db0fc21bc9319d9602aefe1a109d00a7e6cAndy Hung VS_LOG("forall: mVolumeShapers.size() %zu", mVolumeShapers.size()); 8044ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung for (const auto &shaper : mVolumeShapers) { 80539399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung VolumeShaper::Status status = lambda(shaper); 80639399b6b08b4e9fd7eae50e58e93b07216ad697fAndy Hung VS_LOG("forall applying lambda on shaper (%p): %d", &shaper, (int)status); 8074ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung } 8084ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung } 8094ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung 8104ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung void reset() { 8114ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung AutoMutex _l(mLock); 8124ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung mVolumeShapers.clear(); 8137d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung mLastFrame = 0; 8144ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung // keep mVolumeShaperIdCounter as is. 8154ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung } 8164ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung 8174ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung // Sets the configuration id if necessary - This is based on the counter 8184ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung // internal to the VolumeHandler. 8194ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung void setIdIfNecessary(const sp<VolumeShaper::Configuration> &configuration) { 8204ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung if (configuration->getType() == VolumeShaper::Configuration::TYPE_SCALE) { 8214ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung const int id = configuration->getId(); 8224ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung if (id == -1) { 8234ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung // Reassign to a unique id, skipping system ids. 8244ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung AutoMutex _l(mLock); 8254ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung while (true) { 8264ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung if (mVolumeShaperIdCounter == INT32_MAX) { 8274ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung mVolumeShaperIdCounter = VolumeShaper::kSystemIdMax; 8284ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung } else { 8294ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung ++mVolumeShaperIdCounter; 8304ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung } 8314ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung if (findId_l(mVolumeShaperIdCounter) != mVolumeShapers.end()) { 8324ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung continue; // collision with an existing id. 8334ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung } 8344ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung configuration->setId(mVolumeShaperIdCounter); 8354ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung ALOGD("setting id to %d", mVolumeShaperIdCounter); 8364ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung break; 8374ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung } 8384ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung } 8394ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung } 8404ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung } 8414ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung 8429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungprivate: 8439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::list<VolumeShaper>::iterator findId_l(int32_t id) { 8449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::list<VolumeShaper>::iterator it = mVolumeShapers.begin(); 8459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (; it != mVolumeShapers.end(); ++it) { 8469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (it->mConfiguration->getId() == id) { 8479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung break; 8489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 8499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 8509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return it; 8519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 8529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 8539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mutable Mutex mLock; 8549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung double mSampleRate; // in samples (frames) per second 8557d712bb0916182cb73f05ec9144b39314ddd5eabAndy Hung int64_t mLastFrame; // logging purpose only, 0 on start 8564ef88d7106c01f81109ee163cb6789073d80c6aeAndy Hung int32_t mVolumeShaperIdCounter; // a counter to return a unique volume shaper id. 857da540db0fc21bc9319d9602aefe1a109d00a7e6cAndy Hung std::pair<T /* volume */, bool /* active */> mLastVolume; 8589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::list<VolumeShaper> mVolumeShapers; // list provides stable iterators on erase 8599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung}; // VolumeHandler 8609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 8619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung} // namespace android 8629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 8639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#pragma pop_macro("LOG_TAG") 8649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 8659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#endif // ANDROID_VOLUME_SHAPER_H 866