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
22 #include "AudioInputDescriptor.h"
23 #include "EffectDescriptor.h"
24 #include <utils/String8.h>
25
26 #include <AudioPolicyInterface.h>
27 #include "AudioPolicyMix.h"
28 #include "HwModule.h"
29
30 namespace android {
31
dump(String8 * dst,int spaces) const32 void EffectDescriptor::dump(String8 *dst, int spaces) const
33 {
34 dst->appendFormat("Effect ID: %d; Attached to I/O handle: %d; Session: %d;\n",
35 mId, mIo, mSession);
36 dst->appendFormat("%*sMusic Effect? %s; \"%s\"; %s; %s\n", spaces, "",
37 isMusicEffect()? "yes" : "no", mDesc.name,
38 mEnabled ? "Enabled" : "Disabled", mSuspended ? "Suspended" : "Active");
39 }
40
EffectDescriptorCollection()41 EffectDescriptorCollection::EffectDescriptorCollection() :
42 mTotalEffectsCpuLoad(0),
43 mTotalEffectsMemory(0),
44 mTotalEffectsMemoryMaxUsed(0)
45 {
46
47 }
48
registerEffect(const effect_descriptor_t * desc,audio_io_handle_t io,int session,int id,bool isMusicEffect)49 status_t EffectDescriptorCollection::registerEffect(const effect_descriptor_t *desc,
50 audio_io_handle_t io,
51 int session,
52 int id, bool isMusicEffect)
53 {
54 if (getEffect(id) != nullptr) {
55 ALOGW("%s effect %s already registered", __FUNCTION__, desc->name);
56 return INVALID_OPERATION;
57 }
58
59 if (mTotalEffectsMemory + desc->memoryUsage > getMaxEffectsMemory()) {
60 ALOGW("registerEffect() memory limit exceeded for Fx %s, Memory %d KB",
61 desc->name, desc->memoryUsage);
62 return INVALID_OPERATION;
63 }
64 mTotalEffectsMemory += desc->memoryUsage;
65 if (mTotalEffectsMemory > mTotalEffectsMemoryMaxUsed) {
66 mTotalEffectsMemoryMaxUsed = mTotalEffectsMemory;
67 }
68 ALOGV("registerEffect() effect %s, io %d, session %d id %d",
69 desc->name, io, session, id);
70 ALOGV("registerEffect() memory %d, total memory %d", desc->memoryUsage, mTotalEffectsMemory);
71
72 sp<EffectDescriptor> effectDesc =
73 new EffectDescriptor(desc, isMusicEffect, id, io, (audio_session_t)session);
74 add(id, effectDesc);
75
76 return NO_ERROR;
77 }
78
getEffect(int id) const79 sp<EffectDescriptor> EffectDescriptorCollection::getEffect(int id) const
80 {
81 ssize_t index = indexOfKey(id);
82 if (index < 0) {
83 return nullptr;
84 }
85 return valueAt(index);
86 }
87
unregisterEffect(int id)88 status_t EffectDescriptorCollection::unregisterEffect(int id)
89 {
90 sp<EffectDescriptor> effectDesc = getEffect(id);
91 if (effectDesc == nullptr) {
92 ALOGW("%s unknown effect ID %d", __FUNCTION__, id);
93 return INVALID_OPERATION;
94 }
95
96 if (mTotalEffectsMemory < effectDesc->mDesc.memoryUsage) {
97 ALOGW("unregisterEffect() memory %d too big for total %d",
98 effectDesc->mDesc.memoryUsage, mTotalEffectsMemory);
99 effectDesc->mDesc.memoryUsage = mTotalEffectsMemory;
100 }
101 mTotalEffectsMemory -= effectDesc->mDesc.memoryUsage;
102 ALOGV("unregisterEffect() effect %s, ID %d, memory %d total memory %d",
103 effectDesc->mDesc.name, id, effectDesc->mDesc.memoryUsage, mTotalEffectsMemory);
104
105 removeItem(id);
106
107 return NO_ERROR;
108 }
109
setEffectEnabled(int id,bool enabled)110 status_t EffectDescriptorCollection::setEffectEnabled(int id, bool enabled)
111 {
112 ssize_t index = indexOfKey(id);
113 if (index < 0) {
114 ALOGW("unregisterEffect() unknown effect ID %d", id);
115 return INVALID_OPERATION;
116 }
117
118 return setEffectEnabled(valueAt(index), enabled);
119 }
120
isEffectEnabled(int id) const121 bool EffectDescriptorCollection::isEffectEnabled(int id) const
122 {
123 ssize_t index = indexOfKey(id);
124 if (index < 0) {
125 return false;
126 }
127 return valueAt(index)->mEnabled;
128 }
129
setEffectEnabled(const sp<EffectDescriptor> & effectDesc,bool enabled)130 status_t EffectDescriptorCollection::setEffectEnabled(const sp<EffectDescriptor> &effectDesc,
131 bool enabled)
132 {
133 if (enabled == effectDesc->mEnabled) {
134 ALOGV("setEffectEnabled(%s) effect already %s",
135 enabled?"true":"false", enabled?"enabled":"disabled");
136 return INVALID_OPERATION;
137 }
138
139 if (enabled) {
140 if (mTotalEffectsCpuLoad + effectDesc->mDesc.cpuLoad > getMaxEffectsCpuLoad()) {
141 ALOGW("setEffectEnabled(true) CPU Load limit exceeded for Fx %s, CPU %f MIPS",
142 effectDesc->mDesc.name, (float)effectDesc->mDesc.cpuLoad/10);
143 return INVALID_OPERATION;
144 }
145 mTotalEffectsCpuLoad += effectDesc->mDesc.cpuLoad;
146 ALOGV("setEffectEnabled(true) total CPU %d", mTotalEffectsCpuLoad);
147 } else {
148 if (mTotalEffectsCpuLoad < effectDesc->mDesc.cpuLoad) {
149 ALOGW("setEffectEnabled(false) CPU load %d too high for total %d",
150 effectDesc->mDesc.cpuLoad, mTotalEffectsCpuLoad);
151 effectDesc->mDesc.cpuLoad = mTotalEffectsCpuLoad;
152 }
153 mTotalEffectsCpuLoad -= effectDesc->mDesc.cpuLoad;
154 ALOGV("setEffectEnabled(false) total CPU %d", mTotalEffectsCpuLoad);
155 }
156 effectDesc->mEnabled = enabled;
157 return NO_ERROR;
158 }
159
isNonOffloadableEffectEnabled() const160 bool EffectDescriptorCollection::isNonOffloadableEffectEnabled() const
161 {
162 for (size_t i = 0; i < size(); i++) {
163 sp<EffectDescriptor> effectDesc = valueAt(i);
164 if (effectDesc->mEnabled && (effectDesc->isMusicEffect()) &&
165 ((effectDesc->mDesc.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) == 0)) {
166 ALOGV("isNonOffloadableEffectEnabled() non offloadable effect %s enabled on session %d",
167 effectDesc->mDesc.name, effectDesc->mSession);
168 return true;
169 }
170 }
171 return false;
172 }
173
getMaxEffectsCpuLoad() const174 uint32_t EffectDescriptorCollection::getMaxEffectsCpuLoad() const
175 {
176 return MAX_EFFECTS_CPU_LOAD;
177 }
178
getMaxEffectsMemory() const179 uint32_t EffectDescriptorCollection::getMaxEffectsMemory() const
180 {
181 return MAX_EFFECTS_MEMORY;
182 }
183
moveEffects(audio_session_t sessionId,audio_io_handle_t srcIo,audio_io_handle_t dstIo,AudioPolicyClientInterface * clientInterface)184 void EffectDescriptorCollection::moveEffects(audio_session_t sessionId, audio_io_handle_t srcIo,
185 audio_io_handle_t dstIo,
186 AudioPolicyClientInterface *clientInterface)
187 {
188 ALOGV("%s session %d srcIo %d dstIo %d", __func__, sessionId, srcIo, dstIo);
189 for (size_t i = 0; i < size(); i++) {
190 sp<EffectDescriptor> effect = valueAt(i);
191 if (effect->mSession == sessionId && effect->mIo == srcIo) {
192 effect->mIo = dstIo;
193 // Backup enable state before any updatePolicyState call
194 effect->mIsOrphan = (dstIo == AUDIO_IO_HANDLE_NONE);
195 }
196 }
197 clientInterface->moveEffects(sessionId, srcIo, dstIo);
198 }
199
moveEffects(const std::vector<int> & ids,audio_io_handle_t dstIo)200 void EffectDescriptorCollection::moveEffects(const std::vector<int>& ids, audio_io_handle_t dstIo)
201 {
202 ALOGV("%s num effects %zu, first ID %d, dstIo %d",
203 __func__, ids.size(), ids.size() ? ids[0] : 0, dstIo);
204 for (size_t i = 0; i < size(); i++) {
205 sp<EffectDescriptor> effect = valueAt(i);
206 if (std::find(begin(ids), end(ids), effect->mId) != end(ids)) {
207 effect->mIo = dstIo;
208 effect->mIsOrphan = (dstIo == AUDIO_IO_HANDLE_NONE);
209 }
210 }
211 }
212
hasOrphansForSession(audio_session_t sessionId) const213 bool EffectDescriptorCollection::hasOrphansForSession(audio_session_t sessionId) const
214 {
215 for (size_t i = 0; i < size(); ++i) {
216 sp<EffectDescriptor> effect = valueAt(i);
217 if (effect->mSession == sessionId && effect->mIsOrphan) {
218 return true;
219 }
220 }
221 return false;
222 }
223
hasOrphanEffectsForSessionAndType(audio_session_t sessionId,const effect_uuid_t * effectType) const224 bool EffectDescriptorCollection::hasOrphanEffectsForSessionAndType(
225 audio_session_t sessionId, const effect_uuid_t* effectType) const {
226 if (effectType == nullptr) {
227 return hasOrphansForSession(sessionId);
228 }
229
230 for (size_t i = 0; i < size(); ++i) {
231 sp<EffectDescriptor> effect = valueAt(i);
232 if (effect->mIsOrphan && effect->mSession == sessionId &&
233 memcmp(&effect->mDesc.type, effectType, sizeof(effect_uuid_t)) == 0) {
234 return true;
235 }
236 }
237 return false;
238 }
239
getOrphanEffectsForSession(audio_session_t sessionId) const240 EffectDescriptorCollection EffectDescriptorCollection::getOrphanEffectsForSession(
241 audio_session_t sessionId) const
242 {
243 EffectDescriptorCollection effects;
244 for (size_t i = 0; i < size(); i++) {
245 sp<EffectDescriptor> effect = valueAt(i);
246 if (effect->mSession == sessionId && effect->mIsOrphan) {
247 effects.add(keyAt(i), effect);
248 }
249 }
250 return effects;
251 }
252
getIoForSession(audio_session_t sessionId,const effect_uuid_t * effectType) const253 audio_io_handle_t EffectDescriptorCollection::getIoForSession(audio_session_t sessionId,
254 const effect_uuid_t *effectType) const
255 {
256 for (size_t i = 0; i < size(); ++i) {
257 sp<EffectDescriptor> effect = valueAt(i);
258 if (effect->mSession == sessionId && (effectType == nullptr ||
259 memcmp(&effect->mDesc.type, effectType, sizeof(effect_uuid_t)) == 0)) {
260 return effect->mIo;
261 }
262 }
263 return AUDIO_IO_HANDLE_NONE;
264 }
265
moveEffectsForIo(audio_session_t session,audio_io_handle_t dstIo,const AudioInputCollection * inputs,AudioPolicyClientInterface * clientInterface)266 void EffectDescriptorCollection::moveEffectsForIo(audio_session_t session,
267 audio_io_handle_t dstIo, const AudioInputCollection *inputs,
268 AudioPolicyClientInterface *clientInterface)
269 {
270 // No src io: try to find from effect session the src Io to move from
271 audio_io_handle_t srcIo = getIoForSession(session);
272 if (hasOrphansForSession(session) || (srcIo != AUDIO_IO_HANDLE_NONE && srcIo != dstIo)) {
273 moveEffects(session, srcIo, dstIo, inputs, clientInterface);
274 }
275 }
276
moveEffects(audio_session_t session,audio_io_handle_t srcIo,audio_io_handle_t dstIo,const AudioInputCollection * inputs,AudioPolicyClientInterface * clientInterface)277 void EffectDescriptorCollection::moveEffects(audio_session_t session,
278 audio_io_handle_t srcIo, audio_io_handle_t dstIo, const AudioInputCollection *inputs,
279 AudioPolicyClientInterface *clientInterface)
280 {
281 if ((srcIo != AUDIO_IO_HANDLE_NONE && srcIo == dstIo)
282 || (srcIo == AUDIO_IO_HANDLE_NONE && !hasOrphansForSession(session))) {
283 return;
284 }
285 // Either we may find orphan effects for given session or effects for this session might have
286 // been assigned first to another input (it may happen when an input is released or recreated
287 // after client sets its preferred device)
288 EffectDescriptorCollection effectsToMove;
289 if (srcIo == AUDIO_IO_HANDLE_NONE) {
290 ALOGV("%s: restoring effects for session %d from orphan park to io=%d", __func__,
291 session, dstIo);
292 effectsToMove = getOrphanEffectsForSession(session);
293 } else {
294 ALOGV("%s: moving effects for session %d from io=%d to io=%d", __func__, session, srcIo,
295 dstIo);
296 if (const sp<AudioInputDescriptor>& previousInputDesc = inputs->valueFor(srcIo)) {
297 effectsToMove = getEffectsForIo(srcIo);
298 for (size_t i = 0; i < effectsToMove.size(); ++i) {
299 const sp<EffectDescriptor>& effect = effectsToMove.valueAt(i);
300 effect->mEnabledWhenMoved = effect->mEnabled;
301 previousInputDesc->trackEffectEnabled(effect, false);
302 }
303 } else {
304 ALOGW("%s: no effect descriptor for srcIo %d", __func__, srcIo);
305 }
306 }
307 moveEffects(session, srcIo, dstIo, clientInterface);
308
309 if (dstIo != AUDIO_IO_HANDLE_NONE) {
310 if (const sp<AudioInputDescriptor>& inputDesc = inputs->valueFor(dstIo)) {
311 for (size_t i = 0; i < effectsToMove.size(); ++i) {
312 const sp<EffectDescriptor>& effect = effectsToMove.valueAt(i);
313 inputDesc->trackEffectEnabled(effect, effect->mEnabledWhenMoved);
314 }
315 } else {
316 ALOGW("%s: no effect descriptor for dstIo %d", __func__, dstIo);
317 }
318 }
319 }
320
putOrphanEffectsForIo(audio_io_handle_t srcIo)321 void EffectDescriptorCollection::putOrphanEffectsForIo(audio_io_handle_t srcIo)
322 {
323 for (size_t i = 0; i < size(); i++) {
324 sp<EffectDescriptor> effect = valueAt(i);
325 if (effect->mIo == srcIo) {
326 effect->mIo = AUDIO_IO_HANDLE_NONE;
327 effect->mIsOrphan = true;
328 }
329 }
330 }
331
putOrphanEffects(audio_session_t session,audio_io_handle_t srcIo,const AudioInputCollection * inputs,AudioPolicyClientInterface * clientInterface)332 void EffectDescriptorCollection::putOrphanEffects(audio_session_t session,
333 audio_io_handle_t srcIo, const AudioInputCollection *inputs,
334 AudioPolicyClientInterface *clientInterface)
335 {
336 if (getIoForSession(session) != srcIo) {
337 // Effect session not held by this client io handle
338 return;
339 }
340 ALOGV("%s: park effects for session %d and io=%d to orphans", __func__, session, srcIo);
341 moveEffects(session, srcIo, AUDIO_IO_HANDLE_NONE, inputs, clientInterface);
342 }
343
getEffectsForIo(audio_io_handle_t io) const344 EffectDescriptorCollection EffectDescriptorCollection::getEffectsForIo(audio_io_handle_t io) const
345 {
346 EffectDescriptorCollection effects;
347 for (size_t i = 0; i < size(); i++) {
348 if (valueAt(i)->mIo == io) {
349 effects.add(keyAt(i), valueAt(i));
350 }
351 }
352 return effects;
353 }
354
dump(String8 * dst,int spaces,bool verbose) const355 void EffectDescriptorCollection::dump(String8 *dst, int spaces, bool verbose) const
356 {
357 if (verbose) {
358 dst->appendFormat(
359 "\n%*sTotal Effects CPU: %f MIPS, "
360 "Total Effects memory: %d KB, Max memory used: %d KB\n",
361 spaces, "",
362 (float) mTotalEffectsCpuLoad / 10,
363 mTotalEffectsMemory,
364 mTotalEffectsMemoryMaxUsed);
365 }
366 if (size() > 0) {
367 if (spaces > 1) spaces -= 2;
368 dst->appendFormat("%*s- Effects (%zu):\n", spaces, "", size());
369 for (size_t i = 0; i < size(); i++) {
370 const std::string prefix = base::StringPrintf("%*s %zu. ", spaces, "", i + 1);
371 dst->appendFormat("%s", prefix.c_str());
372 valueAt(i)->dump(dst, prefix.size());
373 }
374 }
375 }
376
377 }; //namespace android
378