VolumeShaper.h revision 9fc8b5cd4a64ef07e84c69112461324d5c13a0b0
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 979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Type getType() const { 989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mType; 999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t setType(Type type) { 1029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung switch (type) { 1039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung case TYPE_ID: 1049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung case TYPE_SCALE: 1059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mType = type; 1069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return NO_ERROR; 1079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung default: 1089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("invalid Type: %d", type); 1099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return BAD_VALUE; 1109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung OptionFlag getOptionFlags() const { 1149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mOptionFlags; 1159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t setOptionFlags(OptionFlag optionFlags) { 1189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if ((optionFlags & ~OPTION_FLAG_ALL) != 0) { 1199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("optionFlags has invalid bits: %#x", optionFlags); 1209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return BAD_VALUE; 1219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mOptionFlags = optionFlags; 1239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return NO_ERROR; 1249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung double getDurationMs() const { 1279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mDurationMs; 1289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void setDurationMs(double durationMs) { 1319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mDurationMs = durationMs; 1329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung int32_t getId() const { 1359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mId; 1369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void setId(int32_t id) { 1399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mId = id; 1409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung T adjustVolume(T volume) const { 1439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if ((getOptionFlags() & OPTION_FLAG_VOLUME_IN_DBFS) != 0) { 1449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T out = powf(10.f, volume / 10.); 1459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("in: %f out: %f", volume, out); 1469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung volume = out; 1479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // clamp 1499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (volume < 0.f) { 1509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung volume = 0.f; 1519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else if (volume > 1.f) { 1529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung volume = 1.f; 1539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return volume; 1559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t checkCurve() { 1589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (mType == TYPE_ID) return NO_ERROR; 1599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (this->size() < 2) { 1609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("curve must have at least 2 points"); 1619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return BAD_VALUE; 1629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (first().first != 0.f || last().first != 1.f) { 1649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("curve must start at 0.f and end at 1.f"); 1659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return BAD_VALUE; 1669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if ((getOptionFlags() & OPTION_FLAG_VOLUME_IN_DBFS) != 0) { 1689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (const auto &pt : *this) { 1699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (!(pt.second <= 0.f) /* handle nan */) { 1709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("positive volume dbFS"); 1719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return BAD_VALUE; 1729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else { 1759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (const auto &pt : *this) { 1769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (!(pt.second >= 0.f) || !(pt.second <= 1.f) /* handle nan */) { 1779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("volume < 0.f or > 1.f"); 1789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return BAD_VALUE; 1799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return NO_ERROR; 1839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 1859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void clampVolume() { 1869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if ((mOptionFlags & OPTION_FLAG_VOLUME_IN_DBFS) != 0) { 1879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (auto it = this->begin(); it != this->end(); ++it) { 1889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (!(it->second <= 0.f) /* handle nan */) { 1899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung it->second = 0.f; 1909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else { 1939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (auto it = this->begin(); it != this->end(); ++it) { 1949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (!(it->second >= 0.f) /* handle nan */) { 1959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung it->second = 0.f; 1969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else if (!(it->second <= 1.f)) { 1979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung it->second = 1.f; 1989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 1999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung /* scaleToStartVolume() is used to set the start volume of a 2049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * new VolumeShaper curve, when replacing one VolumeShaper 2059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * with another using the "join" (volume match) option. 2069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * 2079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung * It works best for monotonic volume ramps or ducks. 2089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung */ 2099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void scaleToStartVolume(T volume) { 2109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (this->size() < 2) { 2119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return; 2129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T startVolume = first().second; 2149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T endVolume = last().second; 2159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (endVolume == startVolume) { 2169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // match with linear ramp 2179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T offset = volume - startVolume; 2189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (auto it = this->begin(); it != this->end(); ++it) { 2199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung it->second = it->second + offset * (1.f - it->first); 2209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else { 2229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T scale = (volume - endVolume) / (startVolume - endVolume); 2239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (auto it = this->begin(); it != this->end(); ++it) { 2249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung it->second = scale * (it->second - endVolume) + endVolume; 2259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung clampVolume(); 2289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t writeToParcel(Parcel *parcel) const { 2319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (parcel == nullptr) return BAD_VALUE; 2329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return parcel->writeInt32((int32_t)mType) 2339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: parcel->writeInt32(mId) 2349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: mType == TYPE_ID 2359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ? NO_ERROR 2369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : parcel->writeInt32((int32_t)mOptionFlags) 2379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: parcel->writeDouble(mDurationMs) 2389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: Interpolator<S, T>::writeToParcel(parcel); 2399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t readFromParcel(const Parcel &parcel) { 2429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung int32_t type, optionFlags; 2439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return parcel.readInt32(&type) 2449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: setType((Type)type) 2459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: parcel.readInt32(&mId) 2469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: mType == TYPE_ID 2479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ? NO_ERROR 2489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : parcel.readInt32(&optionFlags) 2499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: setOptionFlags((OptionFlag)optionFlags) 2509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: parcel.readDouble(&mDurationMs) 2519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: Interpolator<S, T>::readFromParcel(parcel) 2529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: checkCurve(); 2539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::string toString() const { 2569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::stringstream ss; 2579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mType: " << mType << std::endl; 2589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mId: " << mId << std::endl; 2599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (mType != TYPE_ID) { 2609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mOptionFlags: " << mOptionFlags << std::endl; 2619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mDurationMs: " << mDurationMs << std::endl; 2629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << Interpolator<S, T>::toString().c_str(); 2639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return ss.str(); 2659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung private: 2689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Type mType; 2699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung int32_t mId; 2709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung OptionFlag mOptionFlags; 2719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung double mDurationMs; 2729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung }; // Configuration 2739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // must match with VolumeShaper.java in frameworks/base 2759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // TODO document per VolumeShaper.java flags. 2769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung class Operation : public RefBase { 2779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung public: 2789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung enum Flag : int32_t { 2799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung FLAG_NONE = 0, 2809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung FLAG_REVERSE = (1 << 0), 2819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung FLAG_TERMINATE = (1 << 1), 2829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung FLAG_JOIN = (1 << 2), 2839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung FLAG_DELAY = (1 << 3), 2849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung FLAG_ALL = (FLAG_REVERSE | FLAG_TERMINATE | FLAG_JOIN | FLAG_DELAY), 2869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung }; 2879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Operation() 2899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : mFlags(FLAG_NONE) 2909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mReplaceId(-1) { 2919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung explicit Operation(Flag flags, int replaceId) 2949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : mFlags(flags) 2959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mReplaceId(replaceId) { 2969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 2979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 2989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung int32_t getReplaceId() const { 2999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mReplaceId; 3009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void setReplaceId(int32_t replaceId) { 3039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mReplaceId = replaceId; 3049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Flag getFlags() const { 3079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mFlags; 3089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t setFlags(Flag flags) { 3119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if ((flags & ~FLAG_ALL) != 0) { 3129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("flags has invalid bits: %#x", flags); 3139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return BAD_VALUE; 3149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mFlags = flags; 3169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return NO_ERROR; 3179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t writeToParcel(Parcel *parcel) const { 3209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (parcel == nullptr) return BAD_VALUE; 3219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return parcel->writeInt32((int32_t)mFlags) 3229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: parcel->writeInt32(mReplaceId); 3239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t readFromParcel(const Parcel &parcel) { 3269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung int32_t flags; 3279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return parcel.readInt32(&flags) 3289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: parcel.readInt32(&mReplaceId) 3299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: setFlags((Flag)flags); 3309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::string toString() const { 3339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::stringstream ss; 3349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mFlags: " << mFlags << std::endl; 3359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mReplaceId: " << mReplaceId << std::endl; 3369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return ss.str(); 3379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung private: 3409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Flag mFlags; 3419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung int32_t mReplaceId; 3429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung }; // Operation 3439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // must match with VolumeShaper.java in frameworks/base 3459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung class State : public RefBase { 3469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung public: 3479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung explicit State(T volume, S xOffset) 3489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : mVolume(volume) 3499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mXOffset(xOffset) { 3509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung State() 3539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : State(-1.f, -1.f) { } 3549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung T getVolume() const { 3569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mVolume; 3579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void setVolume(T volume) { 3609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mVolume = volume; 3619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung S getXOffset() const { 3649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mXOffset; 3659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void setXOffset(S xOffset) { 3689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mXOffset = xOffset; 3699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t writeToParcel(Parcel *parcel) const { 3729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (parcel == nullptr) return BAD_VALUE; 3739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return parcel->writeFloat(mVolume) 3749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: parcel->writeFloat(mXOffset); 3759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung status_t readFromParcel(const Parcel &parcel) { 3789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return parcel.readFloat(&mVolume) 3799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ?: parcel.readFloat(&mXOffset); 3809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::string toString() const { 3839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::stringstream ss; 3849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mVolume: " << mVolume << std::endl; 3859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mXOffset: " << mXOffset << std::endl; 3869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return ss.str(); 3879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 3889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung private: 3909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung T mVolume; 3919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung S mXOffset; 3929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung }; // State 3939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 3949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung template <typename R> 3959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung class Translate { 3969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung public: 3979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Translate() 3989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : mOffset(0) 3999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mScale(1) { 4009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung R getOffset() const { 4039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mOffset; 4049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void setOffset(R offset) { 4079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mOffset = offset; 4089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung R getScale() const { 4119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mScale; 4129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void setScale(R scale) { 4159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mScale = scale; 4169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung R operator()(R in) const { 4199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mScale * (in - mOffset); 4209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::string toString() const { 4239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::stringstream ss; 4249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mOffset: " << mOffset << std::endl; 4259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mScale: " << mScale << std::endl; 4269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return ss.str(); 4279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung private: 4309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung R mOffset; 4319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung R mScale; 4329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung }; // Translate 4339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung static int64_t convertTimespecToUs(const struct timespec &tv) 4359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung { 4369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return tv.tv_sec * 1000000ll + tv.tv_nsec / 1000; 4379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // current monotonic time in microseconds. 4409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung static int64_t getNowUs() 4419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung { 4429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung struct timespec tv; 4439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (clock_gettime(CLOCK_MONOTONIC, &tv) != 0) { 4449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return 0; // system is really sick, just return 0 for consistency. 4459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return convertTimespecToUs(tv); 4479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Translate<S> mXTranslate; 4509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung Translate<T> mYTranslate; 4519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung sp<VolumeShaper::Configuration> mConfiguration; 4529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung sp<VolumeShaper::Operation> mOperation; 4539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung int64_t mStartFrame; 4549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung T mLastVolume; 4559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung S mXOffset; 4569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // TODO: Since we pass configuration and operation as shared pointers 4589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // there is a potential risk that the caller may modify these after 4599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // delivery. Currently, we don't require copies made here. 4609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung explicit VolumeShaper( 4619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const sp<VolumeShaper::Configuration> &configuration, 4629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const sp<VolumeShaper::Operation> &operation) 4639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : mConfiguration(configuration) // we do not make a copy 4649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mOperation(operation) // ditto 4659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mStartFrame(-1) 4669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mLastVolume(T(1)) 4679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mXOffset(0.f) { 4689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (configuration.get() != nullptr 4699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung && (getFlags() & VolumeShaper::Operation::FLAG_DELAY) == 0) { 4709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastVolume = configuration->first().second; 4719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung void updatePosition(int64_t startFrame, double sampleRate) { 4759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung double scale = (mConfiguration->last().first - mConfiguration->first().first) 4769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung / (mConfiguration->getDurationMs() * 0.001 * sampleRate); 4779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const double minScale = 1. / INT64_MAX; 4789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung scale = std::max(scale, minScale); 4799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("update position: scale %lf frameCount:%lld, sampleRate:%lf", 4809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung scale, (long long) startFrame, sampleRate); 4819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mXTranslate.setOffset(startFrame - mConfiguration->first().first / scale); 4829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mXTranslate.setScale(scale); 4839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("translate: %s", mXTranslate.toString().c_str()); 4849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // We allow a null operation here, though VolumeHandler always provides one. 4879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VolumeShaper::Operation::Flag getFlags() const { 4889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return mOperation == nullptr 4899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ? VolumeShaper::Operation::FLAG_NONE :mOperation->getFlags(); 4909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung sp<VolumeShaper::State> getState() const { 4939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return new VolumeShaper::State(mLastVolume, mXOffset); 4949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 4959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 4969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::pair<T, bool> getVolume(int64_t trackFrameCount, double trackSampleRate) { 4979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (mConfiguration.get() == nullptr || mConfiguration->empty()) { 4989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("nonexistent VolumeShaper, removing"); 4999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastVolume = T(1); 5009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mXOffset = 0.f; 5019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return std::make_pair(T(1), true); 5029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if ((getFlags() & VolumeShaper::Operation::FLAG_DELAY) != 0) { 5049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("delayed VolumeShaper, ignoring"); 5059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastVolume = T(1); 5069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mXOffset = 0.; 5079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return std::make_pair(T(1), false); 5089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const bool clockTime = (mConfiguration->getOptionFlags() 5109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung & VolumeShaper::Configuration::OPTION_FLAG_CLOCK_TIME) != 0; 5119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const int64_t frameCount = clockTime ? getNowUs() : trackFrameCount; 5129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const double sampleRate = clockTime ? 1000000 : trackSampleRate; 5139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 5149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (mStartFrame < 0) { 5159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung updatePosition(frameCount, sampleRate); 5169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mStartFrame = frameCount; 5179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("frameCount: %lld", (long long)frameCount); 5199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung S x = mXTranslate((T)frameCount); 5209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("translation: %f", x); 5219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 5229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // handle reversal of position 5239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (getFlags() & VolumeShaper::Operation::FLAG_REVERSE) { 5249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung x = 1.f - x; 5259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("reversing to %f", x); 5269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (x < mConfiguration->first().first) { 5279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mXOffset = 1.f; 5289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T volume = mConfiguration->adjustVolume( 5299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mConfiguration->first().second); // persist last value 5309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("persisting volume %f", volume); 5319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastVolume = volume; 5329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return std::make_pair(volume, false); 5339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (x > mConfiguration->last().first) { 5359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mXOffset = 0.f; 5369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastVolume = 1.f; 5379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return std::make_pair(T(1), false); // too early 5389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else { 5409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (x < mConfiguration->first().first) { 5419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mXOffset = 0.f; 5429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastVolume = 1.f; 5439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return std::make_pair(T(1), false); // too early 5449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (x > mConfiguration->last().first) { 5469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mXOffset = 1.f; 5479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T volume = mConfiguration->adjustVolume( 5489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mConfiguration->last().second); // persist last value 5499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("persisting volume %f", volume); 5509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastVolume = volume; 5519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return std::make_pair(volume, false); 5529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mXOffset = x; 5559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // x contains the location on the volume curve to use. 5569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T unscaledVolume = mConfiguration->findY(x); 5579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T volumeChange = mYTranslate(unscaledVolume); 5589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T volume = mConfiguration->adjustVolume(volumeChange); 5599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("volume: %f unscaled: %f", volume, unscaledVolume); 5609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastVolume = volume; 5619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return std::make_pair(volume, false); 5629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 5649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::string toString() const { 5659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::stringstream ss; 5669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "StartFrame: " << mStartFrame << std::endl; 5679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << mXTranslate.toString().c_str(); 5689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << mYTranslate.toString().c_str(); 5699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (mConfiguration.get() == nullptr) { 5709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "VolumeShaper::Configuration: nullptr" << std::endl; 5719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else { 5729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "VolumeShaper::Configuration:" << std::endl; 5739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << mConfiguration->toString().c_str(); 5749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (mOperation.get() == nullptr) { 5769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "VolumeShaper::Operation: nullptr" << std::endl; 5779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else { 5789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "VolumeShaper::Operation:" << std::endl; 5799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << mOperation->toString().c_str(); 5809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return ss.str(); 5829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung}; // VolumeShaper 5849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 5859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// VolumeHandler combines the volume factors of multiple VolumeShapers and handles 5869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung// multiple thread access by synchronizing all public methods. 5879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungclass VolumeHandler : public RefBase { 5889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungpublic: 5899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung using S = float; 5909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung using T = float; 5919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 5929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung explicit VolumeHandler(uint32_t sampleRate) 5939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung : mSampleRate((double)sampleRate) 5949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung , mLastFrame(0) { 5959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 5969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 5979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VolumeShaper::Status applyVolumeShaper( 5989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const sp<VolumeShaper::Configuration> &configuration, 5999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const sp<VolumeShaper::Operation> &operation) { 6009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung AutoMutex _l(mLock); 6019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (configuration == nullptr) { 6029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("null configuration"); 6039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return VolumeShaper::Status(BAD_VALUE); 6049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (operation == nullptr) { 6069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("null operation"); 6079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return VolumeShaper::Status(BAD_VALUE); 6089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const int32_t id = configuration->getId(); 6109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (id < 0) { 6119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGE("negative id: %d", id); 6129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return VolumeShaper::Status(BAD_VALUE); 6139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("applyVolumeShaper id: %d", id); 6159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 6169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung switch (configuration->getType()) { 6179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung case VolumeShaper::Configuration::TYPE_ID: { 6189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("trying to find id: %d", id); 6199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung auto it = findId_l(id); 6209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (it == mVolumeShapers.end()) { 6219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("couldn't find id: %d\n%s", id, this->toString().c_str()); 6229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return VolumeShaper::Status(INVALID_OPERATION); 6239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if ((it->getFlags() & VolumeShaper::Operation::FLAG_TERMINATE) != 0) { 6259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("terminate id: %d", id); 6269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mVolumeShapers.erase(it); 6279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung break; 6289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if ((it->getFlags() & VolumeShaper::Operation::FLAG_REVERSE) != 6309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung (operation->getFlags() & VolumeShaper::Operation::FLAG_REVERSE)) { 6319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const S x = it->mXTranslate((T)mLastFrame); 6329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("translation: %f", x); 6339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // reflect position 6349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung S target = 1.f - x; 6359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (target < it->mConfiguration->first().first) { 6369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("clamp to start - begin immediately"); 6379fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung target = 0.; 6389fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6399fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung VS_LOG("target: %f", target); 6409fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung it->mXTranslate.setOffset(it->mXTranslate.getOffset() 6419fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung + (x - target) / it->mXTranslate.getScale()); 6429fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6439fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung it->mOperation = operation; // replace the operation 6449fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } break; 6459fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung case VolumeShaper::Configuration::TYPE_SCALE: { 6469fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const int replaceId = operation->getReplaceId(); 6479fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (replaceId >= 0) { 6489fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung auto replaceIt = findId_l(replaceId); 6499fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (replaceIt == mVolumeShapers.end()) { 6509fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGW("cannot find replace id: %d", replaceId); 6519fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } else { 6529fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if ((replaceIt->getFlags() & VolumeShaper::Operation::FLAG_JOIN) != 0) { 6539fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // For join, we scale the start volume of the current configuration 6549fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // to match the last-used volume of the replacing VolumeShaper. 6559fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung auto state = replaceIt->getState(); 6569fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (state->getXOffset() >= 0) { // valid 6579fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung const T volume = state->getVolume(); 6589fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGD("join: scaling start volume to %f", volume); 6599fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung configuration->scaleToStartVolume(volume); 6609fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6619fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6629fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung (void)mVolumeShapers.erase(replaceIt); 6639fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6649fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6659fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // check if we have another of the same id. 6669fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung auto oldIt = findId_l(id); 6679fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (oldIt != mVolumeShapers.end()) { 6689fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ALOGW("duplicate id, removing old %d", id); 6699fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung (void)mVolumeShapers.erase(oldIt); 6709fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6719fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung // create new VolumeShaper 6729fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mVolumeShapers.emplace_back(configuration, operation); 6739fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } break; 6749fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6759fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return VolumeShaper::Status(id); 6769fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6779fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 6789fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung sp<VolumeShaper::State> getVolumeShaperState(int id) { 6799fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung AutoMutex _l(mLock); 6809fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung auto it = findId_l(id); 6819fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (it == mVolumeShapers.end()) { 6829fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return nullptr; 6839fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6849fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return it->getState(); 6859fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6869fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 6879fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung T getVolume(int64_t trackFrameCount) { 6889fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung AutoMutex _l(mLock); 6899fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mLastFrame = trackFrameCount; 6909fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung T volume(1); 6919fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (auto it = mVolumeShapers.begin(); it != mVolumeShapers.end();) { 6929fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::pair<T, bool> shaperVolume = 6939fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung it->getVolume(trackFrameCount, mSampleRate); 6949fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung volume *= shaperVolume.first; 6959fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (shaperVolume.second) { 6969fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung it = mVolumeShapers.erase(it); 6979fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung continue; 6989fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 6999fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ++it; 7009fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 7019fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return volume; 7029fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 7039fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 7049fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::string toString() const { 7059fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung AutoMutex _l(mLock); 7069fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::stringstream ss; 7079fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mSampleRate: " << mSampleRate << std::endl; 7089fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << "mLastFrame: " << mLastFrame << std::endl; 7099fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (const auto &shaper : mVolumeShapers) { 7109fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung ss << shaper.toString().c_str(); 7119fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 7129fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return ss.str(); 7139fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 7149fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 7159fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hungprivate: 7169fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::list<VolumeShaper>::iterator findId_l(int32_t id) { 7179fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::list<VolumeShaper>::iterator it = mVolumeShapers.begin(); 7189fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung for (; it != mVolumeShapers.end(); ++it) { 7199fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung if (it->mConfiguration->getId() == id) { 7209fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung break; 7219fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 7229fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 7239fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung return it; 7249fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung } 7259fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 7269fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung mutable Mutex mLock; 7279fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung double mSampleRate; // in samples (frames) per second 7289fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung int64_t mLastFrame; // logging purpose only 7299fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung std::list<VolumeShaper> mVolumeShapers; // list provides stable iterators on erase 7309fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung}; // VolumeHandler 7319fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 7329fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung} // namespace android 7339fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 7349fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#pragma pop_macro("LOG_TAG") 7359fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung 7369fc8b5cd4a64ef07e84c69112461324d5c13a0b0Andy Hung#endif // ANDROID_VOLUME_SHAPER_H 737