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
getIoForSession(audio_session_t sessionId,const effect_uuid_t * effectType)205 audio_io_handle_t EffectDescriptorCollection::getIoForSession(audio_session_t sessionId,
206 const effect_uuid_t *effectType)
207 {
208 for (size_t i = 0; i < size(); ++i) {
209 sp<EffectDescriptor> effect = valueAt(i);
210 if (effect->mSession == sessionId && (effectType == nullptr ||
211 memcmp(&effect->mDesc.type, effectType, sizeof(effect_uuid_t)) == 0)) {
212 return effect->mIo;
213 }
214 }
215 return AUDIO_IO_HANDLE_NONE;
216 }
217
getEffectsForIo(audio_io_handle_t io) const218 EffectDescriptorCollection EffectDescriptorCollection::getEffectsForIo(audio_io_handle_t io) const
219 {
220 EffectDescriptorCollection effects;
221 for (size_t i = 0; i < size(); i++) {
222 if (valueAt(i)->mIo == io) {
223 effects.add(keyAt(i), valueAt(i));
224 }
225 }
226 return effects;
227 }
228
dump(String8 * dst,int spaces,bool verbose) const229 void EffectDescriptorCollection::dump(String8 *dst, int spaces, bool verbose) const
230 {
231 if (verbose) {
232 dst->appendFormat(
233 "\n%*sTotal Effects CPU: %f MIPS, "
234 "Total Effects memory: %d KB, Max memory used: %d KB\n",
235 spaces, "",
236 (float) mTotalEffectsCpuLoad / 10,
237 mTotalEffectsMemory,
238 mTotalEffectsMemoryMaxUsed);
239 }
240 dst->appendFormat("%*sEffects:\n", spaces, "");
241 for (size_t i = 0; i < size(); i++) {
242 dst->appendFormat("%*s- Effect %d:\n", spaces, "", keyAt(i));
243 valueAt(i)->dump(dst, spaces + 2);
244 }
245 }
246
247 }; //namespace android
248