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
23namespace android {
24
25status_t EffectDescriptor::dump(int fd)
26{
27    const size_t SIZE = 256;
28    char buffer[SIZE];
29    String8 result;
30
31    snprintf(buffer, SIZE, " I/O: %d\n", mIo);
32    result.append(buffer);
33    snprintf(buffer, SIZE, " Strategy: %d\n", mStrategy);
34    result.append(buffer);
35    snprintf(buffer, SIZE, " Session: %d\n", mSession);
36    result.append(buffer);
37    snprintf(buffer, SIZE, " Name: %s\n",  mDesc.name);
38    result.append(buffer);
39    snprintf(buffer, SIZE, " %s\n",  mEnabled ? "Enabled" : "Disabled");
40    result.append(buffer);
41    write(fd, result.string(), result.size());
42
43    return NO_ERROR;
44}
45
46EffectDescriptorCollection::EffectDescriptorCollection() :
47    mTotalEffectsCpuLoad(0),
48    mTotalEffectsMemory(0),
49    mTotalEffectsMemoryMaxUsed(0)
50{
51
52}
53
54status_t EffectDescriptorCollection::registerEffect(const effect_descriptor_t *desc,
55                                                    audio_io_handle_t io,
56                                                    uint32_t strategy,
57                                                    int session,
58                                                    int id)
59{
60    if (mTotalEffectsMemory + desc->memoryUsage > getMaxEffectsMemory()) {
61        ALOGW("registerEffect() memory limit exceeded for Fx %s, Memory %d KB",
62                desc->name, desc->memoryUsage);
63        return INVALID_OPERATION;
64    }
65    mTotalEffectsMemory += desc->memoryUsage;
66    if (mTotalEffectsMemory > mTotalEffectsMemoryMaxUsed) {
67        mTotalEffectsMemoryMaxUsed = mTotalEffectsMemory;
68    }
69    ALOGV("registerEffect() effect %s, io %d, strategy %d session %d id %d",
70            desc->name, io, strategy, session, id);
71    ALOGV("registerEffect() memory %d, total memory %d", desc->memoryUsage, mTotalEffectsMemory);
72
73    sp<EffectDescriptor> effectDesc = new EffectDescriptor();
74    memcpy (&effectDesc->mDesc, desc, sizeof(effect_descriptor_t));
75    effectDesc->mIo = io;
76    effectDesc->mStrategy = static_cast<routing_strategy>(strategy);
77    effectDesc->mSession = session;
78    effectDesc->mEnabled = false;
79
80    add(id, effectDesc);
81
82    return NO_ERROR;
83}
84
85status_t EffectDescriptorCollection::unregisterEffect(int id)
86{
87    ssize_t index = indexOfKey(id);
88    if (index < 0) {
89        ALOGW("unregisterEffect() unknown effect ID %d", id);
90        return INVALID_OPERATION;
91    }
92
93    sp<EffectDescriptor> effectDesc = valueAt(index);
94
95    setEffectEnabled(effectDesc, false);
96
97    if (mTotalEffectsMemory < effectDesc->mDesc.memoryUsage) {
98        ALOGW("unregisterEffect() memory %d too big for total %d",
99                effectDesc->mDesc.memoryUsage, mTotalEffectsMemory);
100        effectDesc->mDesc.memoryUsage = mTotalEffectsMemory;
101    }
102    mTotalEffectsMemory -= effectDesc->mDesc.memoryUsage;
103    ALOGV("unregisterEffect() effect %s, ID %d, memory %d total memory %d",
104            effectDesc->mDesc.name, id, effectDesc->mDesc.memoryUsage, mTotalEffectsMemory);
105
106    removeItem(id);
107
108    return NO_ERROR;
109}
110
111status_t EffectDescriptorCollection::setEffectEnabled(int id, bool enabled)
112{
113    ssize_t index = indexOfKey(id);
114    if (index < 0) {
115        ALOGW("unregisterEffect() unknown effect ID %d", id);
116        return INVALID_OPERATION;
117    }
118
119    return setEffectEnabled(valueAt(index), enabled);
120}
121
122
123status_t EffectDescriptorCollection::setEffectEnabled(const sp<EffectDescriptor> &effectDesc,
124                                                      bool enabled)
125{
126    if (enabled == effectDesc->mEnabled) {
127        ALOGV("setEffectEnabled(%s) effect already %s",
128             enabled?"true":"false", enabled?"enabled":"disabled");
129        return INVALID_OPERATION;
130    }
131
132    if (enabled) {
133        if (mTotalEffectsCpuLoad + effectDesc->mDesc.cpuLoad > getMaxEffectsCpuLoad()) {
134            ALOGW("setEffectEnabled(true) CPU Load limit exceeded for Fx %s, CPU %f MIPS",
135                 effectDesc->mDesc.name, (float)effectDesc->mDesc.cpuLoad/10);
136            return INVALID_OPERATION;
137        }
138        mTotalEffectsCpuLoad += effectDesc->mDesc.cpuLoad;
139        ALOGV("setEffectEnabled(true) total CPU %d", mTotalEffectsCpuLoad);
140    } else {
141        if (mTotalEffectsCpuLoad < effectDesc->mDesc.cpuLoad) {
142            ALOGW("setEffectEnabled(false) CPU load %d too high for total %d",
143                    effectDesc->mDesc.cpuLoad, mTotalEffectsCpuLoad);
144            effectDesc->mDesc.cpuLoad = mTotalEffectsCpuLoad;
145        }
146        mTotalEffectsCpuLoad -= effectDesc->mDesc.cpuLoad;
147        ALOGV("setEffectEnabled(false) total CPU %d", mTotalEffectsCpuLoad);
148    }
149    effectDesc->mEnabled = enabled;
150    return NO_ERROR;
151}
152
153bool EffectDescriptorCollection::isNonOffloadableEffectEnabled()
154{
155    for (size_t i = 0; i < size(); i++) {
156        sp<EffectDescriptor> effectDesc = valueAt(i);
157        if (effectDesc->mEnabled && (effectDesc->mStrategy == STRATEGY_MEDIA) &&
158                ((effectDesc->mDesc.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) == 0)) {
159            ALOGV("isNonOffloadableEffectEnabled() non offloadable effect %s enabled on session %d",
160                  effectDesc->mDesc.name, effectDesc->mSession);
161            return true;
162        }
163    }
164    return false;
165}
166
167uint32_t EffectDescriptorCollection::getMaxEffectsCpuLoad() const
168{
169    return MAX_EFFECTS_CPU_LOAD;
170}
171
172uint32_t EffectDescriptorCollection::getMaxEffectsMemory() const
173{
174    return MAX_EFFECTS_MEMORY;
175}
176
177status_t EffectDescriptorCollection::dump(int fd)
178{
179    const size_t SIZE = 256;
180    char buffer[SIZE];
181
182    snprintf(buffer, SIZE,
183            "\nTotal Effects CPU: %f MIPS, Total Effects memory: %d KB, Max memory used: %d KB\n",
184             (float)mTotalEffectsCpuLoad/10, mTotalEffectsMemory, mTotalEffectsMemoryMaxUsed);
185    write(fd, buffer, strlen(buffer));
186
187    snprintf(buffer, SIZE, "Registered effects:\n");
188    write(fd, buffer, strlen(buffer));
189    for (size_t i = 0; i < size(); i++) {
190        snprintf(buffer, SIZE, "- Effect %d dump:\n", keyAt(i));
191        write(fd, buffer, strlen(buffer));
192        valueAt(i)->dump(fd);
193    }
194    return NO_ERROR;
195}
196
197}; //namespace android
198