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