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 "EffectDescriptor.h"
21 #include <utils/String8.h>
22 
23 namespace android {
24 
dump(String8 * dst,int spaces) const25 void EffectDescriptor::dump(String8 *dst, int spaces) const
26 {
27     dst->appendFormat("%*sID: %d\n", spaces, "", mId);
28     dst->appendFormat("%*sI/O: %d\n", spaces, "", mIo);
29     dst->appendFormat("%*sMusic Effect: %s\n", spaces, "", isMusicEffect()? "yes" : "no");
30     dst->appendFormat("%*sSession: %d\n", spaces, "", mSession);
31     dst->appendFormat("%*sName: %s\n", spaces, "",  mDesc.name);
32     dst->appendFormat("%*s%s\n", spaces, "",  mEnabled ? "Enabled" : "Disabled");
33     dst->appendFormat("%*s%s\n", spaces, "",  mSuspended ? "Suspended" : "Active");
34 }
35 
EffectDescriptorCollection()36 EffectDescriptorCollection::EffectDescriptorCollection() :
37     mTotalEffectsCpuLoad(0),
38     mTotalEffectsMemory(0),
39     mTotalEffectsMemoryMaxUsed(0)
40 {
41 
42 }
43 
registerEffect(const effect_descriptor_t * desc,audio_io_handle_t io,int session,int id,bool isMusicEffect)44 status_t EffectDescriptorCollection::registerEffect(const effect_descriptor_t *desc,
45                                                     audio_io_handle_t io,
46                                                     int session,
47                                                     int id, bool isMusicEffect)
48 {
49     if (getEffect(id) != nullptr) {
50         ALOGW("%s effect %s already registered", __FUNCTION__, desc->name);
51         return INVALID_OPERATION;
52     }
53 
54     if (mTotalEffectsMemory + desc->memoryUsage > getMaxEffectsMemory()) {
55         ALOGW("registerEffect() memory limit exceeded for Fx %s, Memory %d KB",
56                 desc->name, desc->memoryUsage);
57         return INVALID_OPERATION;
58     }
59     mTotalEffectsMemory += desc->memoryUsage;
60     if (mTotalEffectsMemory > mTotalEffectsMemoryMaxUsed) {
61         mTotalEffectsMemoryMaxUsed = mTotalEffectsMemory;
62     }
63     ALOGV("registerEffect() effect %s, io %d, session %d id %d",
64             desc->name, io, session, id);
65     ALOGV("registerEffect() memory %d, total memory %d", desc->memoryUsage, mTotalEffectsMemory);
66 
67     sp<EffectDescriptor> effectDesc =
68         new EffectDescriptor(desc, isMusicEffect, id, io, (audio_session_t)session);
69     add(id, effectDesc);
70 
71     return NO_ERROR;
72 }
73 
getEffect(int id) const74 sp<EffectDescriptor> EffectDescriptorCollection::getEffect(int id) const
75 {
76     ssize_t index = indexOfKey(id);
77     if (index < 0) {
78         return nullptr;
79     }
80     return valueAt(index);
81 }
82 
unregisterEffect(int id)83 status_t EffectDescriptorCollection::unregisterEffect(int id)
84 {
85     sp<EffectDescriptor> effectDesc = getEffect(id);
86     if (effectDesc == nullptr) {
87         ALOGW("%s unknown effect ID %d", __FUNCTION__, id);
88         return INVALID_OPERATION;
89     }
90 
91     if (mTotalEffectsMemory < effectDesc->mDesc.memoryUsage) {
92         ALOGW("unregisterEffect() memory %d too big for total %d",
93                 effectDesc->mDesc.memoryUsage, mTotalEffectsMemory);
94         effectDesc->mDesc.memoryUsage = mTotalEffectsMemory;
95     }
96     mTotalEffectsMemory -= effectDesc->mDesc.memoryUsage;
97     ALOGV("unregisterEffect() effect %s, ID %d, memory %d total memory %d",
98             effectDesc->mDesc.name, id, effectDesc->mDesc.memoryUsage, mTotalEffectsMemory);
99 
100     removeItem(id);
101 
102     return NO_ERROR;
103 }
104 
setEffectEnabled(int id,bool enabled)105 status_t EffectDescriptorCollection::setEffectEnabled(int id, bool enabled)
106 {
107     ssize_t index = indexOfKey(id);
108     if (index < 0) {
109         ALOGW("unregisterEffect() unknown effect ID %d", id);
110         return INVALID_OPERATION;
111     }
112 
113     return setEffectEnabled(valueAt(index), enabled);
114 }
115 
isEffectEnabled(int id) const116 bool EffectDescriptorCollection::isEffectEnabled(int id) const
117 {
118     ssize_t index = indexOfKey(id);
119     if (index < 0) {
120         return false;
121     }
122     return valueAt(index)->mEnabled;
123 }
124 
setEffectEnabled(const sp<EffectDescriptor> & effectDesc,bool enabled)125 status_t EffectDescriptorCollection::setEffectEnabled(const sp<EffectDescriptor> &effectDesc,
126                                                       bool enabled)
127 {
128     if (enabled == effectDesc->mEnabled) {
129         ALOGV("setEffectEnabled(%s) effect already %s",
130              enabled?"true":"false", enabled?"enabled":"disabled");
131         return INVALID_OPERATION;
132     }
133 
134     if (enabled) {
135         if (mTotalEffectsCpuLoad + effectDesc->mDesc.cpuLoad > getMaxEffectsCpuLoad()) {
136             ALOGW("setEffectEnabled(true) CPU Load limit exceeded for Fx %s, CPU %f MIPS",
137                  effectDesc->mDesc.name, (float)effectDesc->mDesc.cpuLoad/10);
138             return INVALID_OPERATION;
139         }
140         mTotalEffectsCpuLoad += effectDesc->mDesc.cpuLoad;
141         ALOGV("setEffectEnabled(true) total CPU %d", mTotalEffectsCpuLoad);
142     } else {
143         if (mTotalEffectsCpuLoad < effectDesc->mDesc.cpuLoad) {
144             ALOGW("setEffectEnabled(false) CPU load %d too high for total %d",
145                     effectDesc->mDesc.cpuLoad, mTotalEffectsCpuLoad);
146             effectDesc->mDesc.cpuLoad = mTotalEffectsCpuLoad;
147         }
148         mTotalEffectsCpuLoad -= effectDesc->mDesc.cpuLoad;
149         ALOGV("setEffectEnabled(false) total CPU %d", mTotalEffectsCpuLoad);
150     }
151     effectDesc->mEnabled = enabled;
152     return NO_ERROR;
153 }
154 
isNonOffloadableEffectEnabled() const155 bool EffectDescriptorCollection::isNonOffloadableEffectEnabled() const
156 {
157     for (size_t i = 0; i < size(); i++) {
158         sp<EffectDescriptor> effectDesc = valueAt(i);
159         if (effectDesc->mEnabled && (effectDesc->isMusicEffect()) &&
160                 ((effectDesc->mDesc.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) == 0)) {
161             ALOGV("isNonOffloadableEffectEnabled() non offloadable effect %s enabled on session %d",
162                   effectDesc->mDesc.name, effectDesc->mSession);
163             return true;
164         }
165     }
166     return false;
167 }
168 
getMaxEffectsCpuLoad() const169 uint32_t EffectDescriptorCollection::getMaxEffectsCpuLoad() const
170 {
171     return MAX_EFFECTS_CPU_LOAD;
172 }
173 
getMaxEffectsMemory() const174 uint32_t EffectDescriptorCollection::getMaxEffectsMemory() const
175 {
176     return MAX_EFFECTS_MEMORY;
177 }
178 
moveEffects(audio_session_t session,audio_io_handle_t srcOutput,audio_io_handle_t dstOutput)179 void EffectDescriptorCollection::moveEffects(audio_session_t session,
180                                              audio_io_handle_t srcOutput,
181                                              audio_io_handle_t dstOutput)
182 {
183     ALOGV("%s session %d srcOutput %d dstOutput %d", __func__, session, srcOutput, dstOutput);
184     for (size_t i = 0; i < size(); i++) {
185         sp<EffectDescriptor> effect = valueAt(i);
186         if (effect->mSession == session && effect->mIo == srcOutput) {
187             effect->mIo = dstOutput;
188         }
189     }
190 }
191 
moveEffects(const std::vector<int> & ids,audio_io_handle_t dstOutput)192 void EffectDescriptorCollection::moveEffects(const std::vector<int>& ids,
193                                              audio_io_handle_t dstOutput)
194 {
195     ALOGV("%s num effects %zu, first ID %d, dstOutput %d",
196         __func__, ids.size(), ids.size() ? ids[0] : 0, dstOutput);
197     for (size_t i = 0; i < size(); i++) {
198         sp<EffectDescriptor> effect = valueAt(i);
199         if (std::find(begin(ids), end(ids), effect->mId) != end(ids)) {
200             effect->mIo = dstOutput;
201         }
202     }
203 }
204 
getEffectsForIo(audio_io_handle_t io) const205 EffectDescriptorCollection EffectDescriptorCollection::getEffectsForIo(audio_io_handle_t io) const
206 {
207     EffectDescriptorCollection effects;
208     for (size_t i = 0; i < size(); i++) {
209         if (valueAt(i)->mIo == io) {
210             effects.add(keyAt(i), valueAt(i));
211         }
212     }
213     return effects;
214 }
215 
dump(String8 * dst,int spaces,bool verbose) const216 void EffectDescriptorCollection::dump(String8 *dst, int spaces, bool verbose) const
217 {
218     if (verbose) {
219         dst->appendFormat(
220             "\n%*sTotal Effects CPU: %f MIPS, "
221             "Total Effects memory: %d KB, Max memory used: %d KB\n",
222             spaces, "",
223             (float) mTotalEffectsCpuLoad / 10,
224             mTotalEffectsMemory,
225             mTotalEffectsMemoryMaxUsed);
226     }
227     dst->appendFormat("%*sEffects:\n", spaces, "");
228     for (size_t i = 0; i < size(); i++) {
229         dst->appendFormat("%*s- Effect %d:\n", spaces, "", keyAt(i));
230         valueAt(i)->dump(dst, spaces + 2);
231     }
232 }
233 
234 }; //namespace android
235