1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "APM::EffectDescriptor"
18 //#define LOG_NDEBUG 0
19
20 #include <android-base/stringprintf.h>
21 #include "EffectDescriptor.h"
22 #include <utils/String8.h>
23
24 namespace android {
25
dump(String8 * dst,int spaces) const26 void EffectDescriptor::dump(String8 *dst, int spaces) const
27 {
28 dst->appendFormat("Effect ID: %d; Attached to I/O handle: %d; Session: %d;\n",
29 mId, mIo, mSession);
30 dst->appendFormat("%*sMusic Effect? %s; \"%s\"; %s; %s\n", spaces, "",
31 isMusicEffect()? "yes" : "no", mDesc.name,
32 mEnabled ? "Enabled" : "Disabled", mSuspended ? "Suspended" : "Active");
33 }
34
EffectDescriptorCollection()35 EffectDescriptorCollection::EffectDescriptorCollection() :
36 mTotalEffectsCpuLoad(0),
37 mTotalEffectsMemory(0),
38 mTotalEffectsMemoryMaxUsed(0)
39 {
40
41 }
42
registerEffect(const effect_descriptor_t * desc,audio_io_handle_t io,int session,int id,bool isMusicEffect)43 status_t EffectDescriptorCollection::registerEffect(const effect_descriptor_t *desc,
44 audio_io_handle_t io,
45 int session,
46 int id, bool isMusicEffect)
47 {
48 if (getEffect(id) != nullptr) {
49 ALOGW("%s effect %s already registered", __FUNCTION__, desc->name);
50 return INVALID_OPERATION;
51 }
52
53 if (mTotalEffectsMemory + desc->memoryUsage > getMaxEffectsMemory()) {
54 ALOGW("registerEffect() memory limit exceeded for Fx %s, Memory %d KB",
55 desc->name, desc->memoryUsage);
56 return INVALID_OPERATION;
57 }
58 mTotalEffectsMemory += desc->memoryUsage;
59 if (mTotalEffectsMemory > mTotalEffectsMemoryMaxUsed) {
60 mTotalEffectsMemoryMaxUsed = mTotalEffectsMemory;
61 }
62 ALOGV("registerEffect() effect %s, io %d, session %d id %d",
63 desc->name, io, session, id);
64 ALOGV("registerEffect() memory %d, total memory %d", desc->memoryUsage, mTotalEffectsMemory);
65
66 sp<EffectDescriptor> effectDesc =
67 new EffectDescriptor(desc, isMusicEffect, id, io, (audio_session_t)session);
68 add(id, effectDesc);
69
70 return NO_ERROR;
71 }
72
getEffect(int id) const73 sp<EffectDescriptor> EffectDescriptorCollection::getEffect(int id) const
74 {
75 ssize_t index = indexOfKey(id);
76 if (index < 0) {
77 return nullptr;
78 }
79 return valueAt(index);
80 }
81
unregisterEffect(int id)82 status_t EffectDescriptorCollection::unregisterEffect(int id)
83 {
84 sp<EffectDescriptor> effectDesc = getEffect(id);
85 if (effectDesc == nullptr) {
86 ALOGW("%s unknown effect ID %d", __FUNCTION__, id);
87 return INVALID_OPERATION;
88 }
89
90 if (mTotalEffectsMemory < effectDesc->mDesc.memoryUsage) {
91 ALOGW("unregisterEffect() memory %d too big for total %d",
92 effectDesc->mDesc.memoryUsage, mTotalEffectsMemory);
93 effectDesc->mDesc.memoryUsage = mTotalEffectsMemory;
94 }
95 mTotalEffectsMemory -= effectDesc->mDesc.memoryUsage;
96 ALOGV("unregisterEffect() effect %s, ID %d, memory %d total memory %d",
97 effectDesc->mDesc.name, id, effectDesc->mDesc.memoryUsage, mTotalEffectsMemory);
98
99 removeItem(id);
100
101 return NO_ERROR;
102 }
103
setEffectEnabled(int id,bool enabled)104 status_t EffectDescriptorCollection::setEffectEnabled(int id, bool enabled)
105 {
106 ssize_t index = indexOfKey(id);
107 if (index < 0) {
108 ALOGW("unregisterEffect() unknown effect ID %d", id);
109 return INVALID_OPERATION;
110 }
111
112 return setEffectEnabled(valueAt(index), enabled);
113 }
114
isEffectEnabled(int id) const115 bool EffectDescriptorCollection::isEffectEnabled(int id) const
116 {
117 ssize_t index = indexOfKey(id);
118 if (index < 0) {
119 return false;
120 }
121 return valueAt(index)->mEnabled;
122 }
123
setEffectEnabled(const sp<EffectDescriptor> & effectDesc,bool enabled)124 status_t EffectDescriptorCollection::setEffectEnabled(const sp<EffectDescriptor> &effectDesc,
125 bool enabled)
126 {
127 if (enabled == effectDesc->mEnabled) {
128 ALOGV("setEffectEnabled(%s) effect already %s",
129 enabled?"true":"false", enabled?"enabled":"disabled");
130 return INVALID_OPERATION;
131 }
132
133 if (enabled) {
134 if (mTotalEffectsCpuLoad + effectDesc->mDesc.cpuLoad > getMaxEffectsCpuLoad()) {
135 ALOGW("setEffectEnabled(true) CPU Load limit exceeded for Fx %s, CPU %f MIPS",
136 effectDesc->mDesc.name, (float)effectDesc->mDesc.cpuLoad/10);
137 return INVALID_OPERATION;
138 }
139 mTotalEffectsCpuLoad += effectDesc->mDesc.cpuLoad;
140 ALOGV("setEffectEnabled(true) total CPU %d", mTotalEffectsCpuLoad);
141 } else {
142 if (mTotalEffectsCpuLoad < effectDesc->mDesc.cpuLoad) {
143 ALOGW("setEffectEnabled(false) CPU load %d too high for total %d",
144 effectDesc->mDesc.cpuLoad, mTotalEffectsCpuLoad);
145 effectDesc->mDesc.cpuLoad = mTotalEffectsCpuLoad;
146 }
147 mTotalEffectsCpuLoad -= effectDesc->mDesc.cpuLoad;
148 ALOGV("setEffectEnabled(false) total CPU %d", mTotalEffectsCpuLoad);
149 }
150 effectDesc->mEnabled = enabled;
151 return NO_ERROR;
152 }
153
isNonOffloadableEffectEnabled() const154 bool EffectDescriptorCollection::isNonOffloadableEffectEnabled() const
155 {
156 for (size_t i = 0; i < size(); i++) {
157 sp<EffectDescriptor> effectDesc = valueAt(i);
158 if (effectDesc->mEnabled && (effectDesc->isMusicEffect()) &&
159 ((effectDesc->mDesc.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) == 0)) {
160 ALOGV("isNonOffloadableEffectEnabled() non offloadable effect %s enabled on session %d",
161 effectDesc->mDesc.name, effectDesc->mSession);
162 return true;
163 }
164 }
165 return false;
166 }
167
getMaxEffectsCpuLoad() const168 uint32_t EffectDescriptorCollection::getMaxEffectsCpuLoad() const
169 {
170 return MAX_EFFECTS_CPU_LOAD;
171 }
172
getMaxEffectsMemory() const173 uint32_t EffectDescriptorCollection::getMaxEffectsMemory() const
174 {
175 return MAX_EFFECTS_MEMORY;
176 }
177
moveEffects(audio_session_t session,audio_io_handle_t srcOutput,audio_io_handle_t dstOutput)178 void EffectDescriptorCollection::moveEffects(audio_session_t session,
179 audio_io_handle_t srcOutput,
180 audio_io_handle_t dstOutput)
181 {
182 ALOGV("%s session %d srcOutput %d dstOutput %d", __func__, session, srcOutput, dstOutput);
183 for (size_t i = 0; i < size(); i++) {
184 sp<EffectDescriptor> effect = valueAt(i);
185 if (effect->mSession == session && effect->mIo == srcOutput) {
186 effect->mIo = dstOutput;
187 }
188 }
189 }
190
moveEffects(const std::vector<int> & ids,audio_io_handle_t dstOutput)191 void EffectDescriptorCollection::moveEffects(const std::vector<int>& ids,
192 audio_io_handle_t dstOutput)
193 {
194 ALOGV("%s num effects %zu, first ID %d, dstOutput %d",
195 __func__, ids.size(), ids.size() ? ids[0] : 0, dstOutput);
196 for (size_t i = 0; i < size(); i++) {
197 sp<EffectDescriptor> effect = valueAt(i);
198 if (std::find(begin(ids), end(ids), effect->mId) != end(ids)) {
199 effect->mIo = dstOutput;
200 }
201 }
202 }
203
getIoForSession(audio_session_t sessionId,const effect_uuid_t * effectType)204 audio_io_handle_t EffectDescriptorCollection::getIoForSession(audio_session_t sessionId,
205 const effect_uuid_t *effectType)
206 {
207 for (size_t i = 0; i < size(); ++i) {
208 sp<EffectDescriptor> effect = valueAt(i);
209 if (effect->mSession == sessionId && (effectType == nullptr ||
210 memcmp(&effect->mDesc.type, effectType, sizeof(effect_uuid_t)) == 0)) {
211 return effect->mIo;
212 }
213 }
214 return AUDIO_IO_HANDLE_NONE;
215 }
216
getEffectsForIo(audio_io_handle_t io) const217 EffectDescriptorCollection EffectDescriptorCollection::getEffectsForIo(audio_io_handle_t io) const
218 {
219 EffectDescriptorCollection effects;
220 for (size_t i = 0; i < size(); i++) {
221 if (valueAt(i)->mIo == io) {
222 effects.add(keyAt(i), valueAt(i));
223 }
224 }
225 return effects;
226 }
227
dump(String8 * dst,int spaces,bool verbose) const228 void EffectDescriptorCollection::dump(String8 *dst, int spaces, bool verbose) const
229 {
230 if (verbose) {
231 dst->appendFormat(
232 "\n%*sTotal Effects CPU: %f MIPS, "
233 "Total Effects memory: %d KB, Max memory used: %d KB\n",
234 spaces, "",
235 (float) mTotalEffectsCpuLoad / 10,
236 mTotalEffectsMemory,
237 mTotalEffectsMemoryMaxUsed);
238 }
239 if (size() > 0) {
240 if (spaces > 1) spaces -= 2;
241 dst->appendFormat("%*s- Effects (%zu):\n", spaces, "", size());
242 for (size_t i = 0; i < size(); i++) {
243 const std::string prefix = base::StringPrintf("%*s %zu. ", spaces, "", i + 1);
244 dst->appendFormat("%s", prefix.c_str());
245 valueAt(i)->dump(dst, prefix.size());
246 }
247 }
248 }
249
250 }; //namespace android
251