blob: 1ec0c5e3ba027b565ff2e8f3fedb0e0db76f07ba [file] [log] [blame]
bryant_liuba2b4392014-06-11 16:49:30 +08001/*
2 * Copyright (C) 2014 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 "AudioPolicyEffects"
Eric Laurent897a4082014-07-11 16:51:53 -070018//#define LOG_NDEBUG 0
bryant_liuba2b4392014-06-11 16:49:30 +080019
20#include <stdlib.h>
21#include <stdio.h>
22#include <string.h>
Kevin Rocard4fb615c2017-06-26 10:28:13 -070023#include <memory>
bryant_liuba2b4392014-06-11 16:49:30 +080024#include <cutils/misc.h>
25#include <media/AudioEffect.h>
Kevin Rocard4fb615c2017-06-26 10:28:13 -070026#include <media/EffectsConfig.h>
Andy Hungab7ef302018-05-15 19:35:29 -070027#include <mediautils/ServiceUtilities.h>
bryant_liuba2b4392014-06-11 16:49:30 +080028#include <system/audio.h>
Mikhail Naganovc2f710f2016-10-17 18:05:36 -070029#include <system/audio_effects/audio_effects_conf.h>
bryant_liuba2b4392014-06-11 16:49:30 +080030#include <utils/Vector.h>
31#include <utils/SortedVector.h>
32#include <cutils/config_utils.h>
Eric Laurentb6436272016-12-07 19:24:50 -080033#include <binder/IPCThreadState.h>
bryant_liuba2b4392014-06-11 16:49:30 +080034#include "AudioPolicyEffects.h"
bryant_liuba2b4392014-06-11 16:49:30 +080035
36namespace android {
37
38// ----------------------------------------------------------------------------
39// AudioPolicyEffects Implementation
40// ----------------------------------------------------------------------------
41
42AudioPolicyEffects::AudioPolicyEffects()
43{
Kevin Rocard4fb615c2017-06-26 10:28:13 -070044 status_t loadResult = loadAudioEffectXmlConfig();
François Gaffiee8e0e7a2020-01-07 15:16:14 +010045 if (loadResult == NO_ERROR) {
46 mDefaultDeviceEffectFuture = std::async(
47 std::launch::async, &AudioPolicyEffects::initDefaultDeviceEffects, this);
48 } else if (loadResult < 0) {
Kevin Rocard4fb615c2017-06-26 10:28:13 -070049 ALOGW("Failed to load XML effect configuration, fallback to .conf");
50 // load automatic audio effect modules
51 if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) {
52 loadAudioEffectConfig(AUDIO_EFFECT_VENDOR_CONFIG_FILE);
53 } else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) {
54 loadAudioEffectConfig(AUDIO_EFFECT_DEFAULT_CONFIG_FILE);
55 }
56 } else if (loadResult > 0) {
57 ALOGE("Effect config is partially invalid, skipped %d elements", loadResult);
bryant_liuba2b4392014-06-11 16:49:30 +080058 }
59}
60
61
62AudioPolicyEffects::~AudioPolicyEffects()
63{
64 size_t i = 0;
65 // release audio input processing resources
66 for (i = 0; i < mInputSources.size(); i++) {
67 delete mInputSources.valueAt(i);
68 }
69 mInputSources.clear();
70
Eric Laurentfb66dd92016-01-28 18:32:03 -080071 for (i = 0; i < mInputSessions.size(); i++) {
72 mInputSessions.valueAt(i)->mEffects.clear();
73 delete mInputSessions.valueAt(i);
bryant_liuba2b4392014-06-11 16:49:30 +080074 }
Eric Laurentfb66dd92016-01-28 18:32:03 -080075 mInputSessions.clear();
bryant_liuba2b4392014-06-11 16:49:30 +080076
77 // release audio output processing resources
78 for (i = 0; i < mOutputStreams.size(); i++) {
79 delete mOutputStreams.valueAt(i);
80 }
81 mOutputStreams.clear();
82
83 for (i = 0; i < mOutputSessions.size(); i++) {
84 mOutputSessions.valueAt(i)->mEffects.clear();
85 delete mOutputSessions.valueAt(i);
86 }
87 mOutputSessions.clear();
88}
89
90
91status_t AudioPolicyEffects::addInputEffects(audio_io_handle_t input,
92 audio_source_t inputSource,
Eric Laurentfb66dd92016-01-28 18:32:03 -080093 audio_session_t audioSession)
bryant_liuba2b4392014-06-11 16:49:30 +080094{
95 status_t status = NO_ERROR;
96
97 // create audio pre processors according to input source
98 audio_source_t aliasSource = (inputSource == AUDIO_SOURCE_HOTWORD) ?
99 AUDIO_SOURCE_VOICE_RECOGNITION : inputSource;
100
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700101 Mutex::Autolock _l(mLock);
bryant_liuba2b4392014-06-11 16:49:30 +0800102 ssize_t index = mInputSources.indexOfKey(aliasSource);
103 if (index < 0) {
104 ALOGV("addInputEffects(): no processing needs to be attached to this source");
105 return status;
106 }
Eric Laurentfb66dd92016-01-28 18:32:03 -0800107 ssize_t idx = mInputSessions.indexOfKey(audioSession);
108 EffectVector *sessionDesc;
bryant_liuba2b4392014-06-11 16:49:30 +0800109 if (idx < 0) {
Eric Laurentfb66dd92016-01-28 18:32:03 -0800110 sessionDesc = new EffectVector(audioSession);
111 mInputSessions.add(audioSession, sessionDesc);
bryant_liuba2b4392014-06-11 16:49:30 +0800112 } else {
bryant_liu890a5632014-08-20 18:06:13 +0800113 // EffectVector is existing and we just need to increase ref count
Eric Laurentfb66dd92016-01-28 18:32:03 -0800114 sessionDesc = mInputSessions.valueAt(idx);
bryant_liuba2b4392014-06-11 16:49:30 +0800115 }
Eric Laurentfb66dd92016-01-28 18:32:03 -0800116 sessionDesc->mRefCount++;
bryant_liu890a5632014-08-20 18:06:13 +0800117
Eric Laurentfb66dd92016-01-28 18:32:03 -0800118 ALOGV("addInputEffects(): input: %d, refCount: %d", input, sessionDesc->mRefCount);
119 if (sessionDesc->mRefCount == 1) {
Eric Laurentb6436272016-12-07 19:24:50 -0800120 int64_t token = IPCThreadState::self()->clearCallingIdentity();
Eric Laurent7de5ac12014-10-21 09:07:11 -0700121 Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects;
122 for (size_t i = 0; i < effects.size(); i++) {
123 EffectDesc *effect = effects[i];
Svet Ganovbe71aa22015-04-28 12:06:02 -0700124 sp<AudioEffect> fx = new AudioEffect(NULL, String16("android"), &effect->mUuid, -1, 0,
125 0, audioSession, input);
Eric Laurent7de5ac12014-10-21 09:07:11 -0700126 status_t status = fx->initCheck();
127 if (status != NO_ERROR && status != ALREADY_EXISTS) {
128 ALOGW("addInputEffects(): failed to create Fx %s on source %d",
129 effect->mName, (int32_t)aliasSource);
130 // fx goes out of scope and strong ref on AudioEffect is released
131 continue;
132 }
133 for (size_t j = 0; j < effect->mParams.size(); j++) {
134 fx->setParameter(effect->mParams[j]);
135 }
136 ALOGV("addInputEffects(): added Fx %s on source: %d",
bryant_liuba2b4392014-06-11 16:49:30 +0800137 effect->mName, (int32_t)aliasSource);
Eric Laurentfb66dd92016-01-28 18:32:03 -0800138 sessionDesc->mEffects.add(fx);
bryant_liuba2b4392014-06-11 16:49:30 +0800139 }
Eric Laurentfb66dd92016-01-28 18:32:03 -0800140 sessionDesc->setProcessorEnabled(true);
Eric Laurentb6436272016-12-07 19:24:50 -0800141 IPCThreadState::self()->restoreCallingIdentity(token);
bryant_liuba2b4392014-06-11 16:49:30 +0800142 }
bryant_liuba2b4392014-06-11 16:49:30 +0800143 return status;
144}
145
146
Eric Laurentfb66dd92016-01-28 18:32:03 -0800147status_t AudioPolicyEffects::releaseInputEffects(audio_io_handle_t input,
148 audio_session_t audioSession)
bryant_liuba2b4392014-06-11 16:49:30 +0800149{
150 status_t status = NO_ERROR;
151
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700152 Mutex::Autolock _l(mLock);
Eric Laurentfb66dd92016-01-28 18:32:03 -0800153 ssize_t index = mInputSessions.indexOfKey(audioSession);
bryant_liuba2b4392014-06-11 16:49:30 +0800154 if (index < 0) {
155 return status;
156 }
Eric Laurentfb66dd92016-01-28 18:32:03 -0800157 EffectVector *sessionDesc = mInputSessions.valueAt(index);
158 sessionDesc->mRefCount--;
159 ALOGV("releaseInputEffects(): input: %d, refCount: %d", input, sessionDesc->mRefCount);
160 if (sessionDesc->mRefCount == 0) {
161 sessionDesc->setProcessorEnabled(false);
162 delete sessionDesc;
163 mInputSessions.removeItemsAt(index);
bryant_liu890a5632014-08-20 18:06:13 +0800164 ALOGV("releaseInputEffects(): all effects released");
165 }
bryant_liuba2b4392014-06-11 16:49:30 +0800166 return status;
167}
168
Eric Laurentfb66dd92016-01-28 18:32:03 -0800169status_t AudioPolicyEffects::queryDefaultInputEffects(audio_session_t audioSession,
bryant_liuba2b4392014-06-11 16:49:30 +0800170 effect_descriptor_t *descriptors,
171 uint32_t *count)
172{
173 status_t status = NO_ERROR;
174
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700175 Mutex::Autolock _l(mLock);
bryant_liuba2b4392014-06-11 16:49:30 +0800176 size_t index;
Eric Laurentfb66dd92016-01-28 18:32:03 -0800177 for (index = 0; index < mInputSessions.size(); index++) {
178 if (mInputSessions.valueAt(index)->mSessionId == audioSession) {
bryant_liuba2b4392014-06-11 16:49:30 +0800179 break;
180 }
181 }
Eric Laurentfb66dd92016-01-28 18:32:03 -0800182 if (index == mInputSessions.size()) {
bryant_liuba2b4392014-06-11 16:49:30 +0800183 *count = 0;
184 return BAD_VALUE;
185 }
Eric Laurentfb66dd92016-01-28 18:32:03 -0800186 Vector< sp<AudioEffect> > effects = mInputSessions.valueAt(index)->mEffects;
bryant_liuba2b4392014-06-11 16:49:30 +0800187
188 for (size_t i = 0; i < effects.size(); i++) {
189 effect_descriptor_t desc = effects[i]->descriptor();
190 if (i < *count) {
191 descriptors[i] = desc;
192 }
193 }
194 if (effects.size() > *count) {
195 status = NO_MEMORY;
196 }
197 *count = effects.size();
198 return status;
199}
200
201
Eric Laurentfb66dd92016-01-28 18:32:03 -0800202status_t AudioPolicyEffects::queryDefaultOutputSessionEffects(audio_session_t audioSession,
bryant_liuba2b4392014-06-11 16:49:30 +0800203 effect_descriptor_t *descriptors,
204 uint32_t *count)
205{
206 status_t status = NO_ERROR;
207
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700208 Mutex::Autolock _l(mLock);
bryant_liuba2b4392014-06-11 16:49:30 +0800209 size_t index;
210 for (index = 0; index < mOutputSessions.size(); index++) {
211 if (mOutputSessions.valueAt(index)->mSessionId == audioSession) {
212 break;
213 }
214 }
215 if (index == mOutputSessions.size()) {
216 *count = 0;
217 return BAD_VALUE;
218 }
219 Vector< sp<AudioEffect> > effects = mOutputSessions.valueAt(index)->mEffects;
220
221 for (size_t i = 0; i < effects.size(); i++) {
222 effect_descriptor_t desc = effects[i]->descriptor();
223 if (i < *count) {
224 descriptors[i] = desc;
225 }
226 }
227 if (effects.size() > *count) {
228 status = NO_MEMORY;
229 }
230 *count = effects.size();
231 return status;
232}
233
234
235status_t AudioPolicyEffects::addOutputSessionEffects(audio_io_handle_t output,
236 audio_stream_type_t stream,
Eric Laurentfb66dd92016-01-28 18:32:03 -0800237 audio_session_t audioSession)
bryant_liuba2b4392014-06-11 16:49:30 +0800238{
239 status_t status = NO_ERROR;
240
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700241 Mutex::Autolock _l(mLock);
bryant_liuba2b4392014-06-11 16:49:30 +0800242 // create audio processors according to stream
Eric Laurent223fd5c2014-11-11 13:43:36 -0800243 // FIXME: should we have specific post processing settings for internal streams?
244 // default to media for now.
245 if (stream >= AUDIO_STREAM_PUBLIC_CNT) {
246 stream = AUDIO_STREAM_MUSIC;
247 }
bryant_liuba2b4392014-06-11 16:49:30 +0800248 ssize_t index = mOutputStreams.indexOfKey(stream);
249 if (index < 0) {
250 ALOGV("addOutputSessionEffects(): no output processing needed for this stream");
251 return NO_ERROR;
252 }
253
254 ssize_t idx = mOutputSessions.indexOfKey(audioSession);
255 EffectVector *procDesc;
256 if (idx < 0) {
257 procDesc = new EffectVector(audioSession);
258 mOutputSessions.add(audioSession, procDesc);
259 } else {
bryant_liu890a5632014-08-20 18:06:13 +0800260 // EffectVector is existing and we just need to increase ref count
bryant_liuba2b4392014-06-11 16:49:30 +0800261 procDesc = mOutputSessions.valueAt(idx);
262 }
bryant_liu890a5632014-08-20 18:06:13 +0800263 procDesc->mRefCount++;
264
Eric Laurent7de5ac12014-10-21 09:07:11 -0700265 ALOGV("addOutputSessionEffects(): session: %d, refCount: %d",
266 audioSession, procDesc->mRefCount);
267 if (procDesc->mRefCount == 1) {
Eric Laurentb6436272016-12-07 19:24:50 -0800268 // make sure effects are associated to audio server even if we are executing a binder call
269 int64_t token = IPCThreadState::self()->clearCallingIdentity();
Eric Laurent7de5ac12014-10-21 09:07:11 -0700270 Vector <EffectDesc *> effects = mOutputStreams.valueAt(index)->mEffects;
271 for (size_t i = 0; i < effects.size(); i++) {
272 EffectDesc *effect = effects[i];
Svet Ganovbe71aa22015-04-28 12:06:02 -0700273 sp<AudioEffect> fx = new AudioEffect(NULL, String16("android"), &effect->mUuid, 0, 0, 0,
Eric Laurent7de5ac12014-10-21 09:07:11 -0700274 audioSession, output);
275 status_t status = fx->initCheck();
276 if (status != NO_ERROR && status != ALREADY_EXISTS) {
277 ALOGE("addOutputSessionEffects(): failed to create Fx %s on session %d",
278 effect->mName, audioSession);
279 // fx goes out of scope and strong ref on AudioEffect is released
280 continue;
281 }
282 ALOGV("addOutputSessionEffects(): added Fx %s on session: %d for stream: %d",
283 effect->mName, audioSession, (int32_t)stream);
284 procDesc->mEffects.add(fx);
bryant_liuba2b4392014-06-11 16:49:30 +0800285 }
Eric Laurent7de5ac12014-10-21 09:07:11 -0700286
287 procDesc->setProcessorEnabled(true);
Eric Laurentb6436272016-12-07 19:24:50 -0800288 IPCThreadState::self()->restoreCallingIdentity(token);
bryant_liuba2b4392014-06-11 16:49:30 +0800289 }
bryant_liuba2b4392014-06-11 16:49:30 +0800290 return status;
291}
292
293status_t AudioPolicyEffects::releaseOutputSessionEffects(audio_io_handle_t output,
294 audio_stream_type_t stream,
Eric Laurentfb66dd92016-01-28 18:32:03 -0800295 audio_session_t audioSession)
bryant_liuba2b4392014-06-11 16:49:30 +0800296{
297 status_t status = NO_ERROR;
298 (void) output; // argument not used for now
299 (void) stream; // argument not used for now
300
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700301 Mutex::Autolock _l(mLock);
bryant_liuba2b4392014-06-11 16:49:30 +0800302 ssize_t index = mOutputSessions.indexOfKey(audioSession);
303 if (index < 0) {
304 ALOGV("releaseOutputSessionEffects: no output processing was attached to this stream");
305 return NO_ERROR;
306 }
307
308 EffectVector *procDesc = mOutputSessions.valueAt(index);
bryant_liu890a5632014-08-20 18:06:13 +0800309 procDesc->mRefCount--;
Eric Laurent7de5ac12014-10-21 09:07:11 -0700310 ALOGV("releaseOutputSessionEffects(): session: %d, refCount: %d",
311 audioSession, procDesc->mRefCount);
bryant_liu890a5632014-08-20 18:06:13 +0800312 if (procDesc->mRefCount == 0) {
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700313 procDesc->setProcessorEnabled(false);
bryant_liu890a5632014-08-20 18:06:13 +0800314 procDesc->mEffects.clear();
315 delete procDesc;
316 mOutputSessions.removeItemsAt(index);
317 ALOGV("releaseOutputSessionEffects(): output processing released from session: %d",
318 audioSession);
319 }
bryant_liuba2b4392014-06-11 16:49:30 +0800320 return status;
321}
322
Ari Hausman-Cohen24628312018-08-13 15:01:09 -0700323status_t AudioPolicyEffects::addSourceDefaultEffect(const effect_uuid_t *type,
324 const String16& opPackageName,
325 const effect_uuid_t *uuid,
326 int32_t priority,
327 audio_source_t source,
328 audio_unique_id_t* id)
329{
330 if (uuid == NULL || type == NULL) {
331 ALOGE("addSourceDefaultEffect(): Null uuid or type uuid pointer");
332 return BAD_VALUE;
333 }
334
Eric Laurentae4b6ec2019-01-15 18:34:38 -0800335 // HOTWORD, FM_TUNER and ECHO_REFERENCE are special case sources > MAX.
Ari Hausman-Cohen24628312018-08-13 15:01:09 -0700336 if (source < AUDIO_SOURCE_DEFAULT ||
337 (source > AUDIO_SOURCE_MAX &&
338 source != AUDIO_SOURCE_HOTWORD &&
Eric Laurentae4b6ec2019-01-15 18:34:38 -0800339 source != AUDIO_SOURCE_FM_TUNER &&
340 source != AUDIO_SOURCE_ECHO_REFERENCE)) {
Ari Hausman-Cohen24628312018-08-13 15:01:09 -0700341 ALOGE("addSourceDefaultEffect(): Unsupported source type %d", source);
342 return BAD_VALUE;
343 }
344
345 // Check that |uuid| or |type| corresponds to an effect on the system.
346 effect_descriptor_t descriptor = {};
347 status_t res = AudioEffect::getEffectDescriptor(
348 uuid, type, EFFECT_FLAG_TYPE_PRE_PROC, &descriptor);
349 if (res != OK) {
350 ALOGE("addSourceDefaultEffect(): Failed to find effect descriptor matching uuid/type.");
351 return res;
352 }
353
354 // Only pre-processing effects can be added dynamically as source defaults.
355 if ((descriptor.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_PRE_PROC) {
356 ALOGE("addSourceDefaultEffect(): Desired effect cannot be attached "
357 "as a source default effect.");
358 return BAD_VALUE;
359 }
360
361 Mutex::Autolock _l(mLock);
362
363 // Find the EffectDescVector for the given source type, or create a new one if necessary.
364 ssize_t index = mInputSources.indexOfKey(source);
365 EffectDescVector *desc = NULL;
366 if (index < 0) {
367 // No effects for this source type yet.
368 desc = new EffectDescVector();
369 mInputSources.add(source, desc);
370 } else {
371 desc = mInputSources.valueAt(index);
372 }
373
374 // Create a new effect and add it to the vector.
375 res = AudioEffect::newEffectUniqueId(id);
376 if (res != OK) {
377 ALOGE("addSourceDefaultEffect(): failed to get new unique id.");
378 return res;
379 }
380 EffectDesc *effect = new EffectDesc(
381 descriptor.name, *type, opPackageName, *uuid, priority, *id);
382 desc->mEffects.add(effect);
383 // TODO(b/71813697): Support setting params as well.
384
385 // TODO(b/71814300): Retroactively attach to any existing sources of the given type.
386 // This requires tracking the source type of each session id in addition to what is
387 // already being tracked.
388
389 return NO_ERROR;
390}
391
Ari Hausman-Cohen433722e2018-04-24 14:25:22 -0700392status_t AudioPolicyEffects::addStreamDefaultEffect(const effect_uuid_t *type,
393 const String16& opPackageName,
394 const effect_uuid_t *uuid,
395 int32_t priority,
396 audio_usage_t usage,
397 audio_unique_id_t* id)
398{
399 if (uuid == NULL || type == NULL) {
400 ALOGE("addStreamDefaultEffect(): Null uuid or type uuid pointer");
401 return BAD_VALUE;
402 }
François Gaffie58d4be52018-11-06 15:30:12 +0100403 audio_stream_type_t stream = AudioSystem::attributesToStreamType(attributes_initializer(usage));
Ari Hausman-Cohen433722e2018-04-24 14:25:22 -0700404
405 if (stream < AUDIO_STREAM_MIN || stream >= AUDIO_STREAM_PUBLIC_CNT) {
406 ALOGE("addStreamDefaultEffect(): Unsupported stream type %d", stream);
407 return BAD_VALUE;
408 }
409
410 // Check that |uuid| or |type| corresponds to an effect on the system.
411 effect_descriptor_t descriptor = {};
412 status_t res = AudioEffect::getEffectDescriptor(
413 uuid, type, EFFECT_FLAG_TYPE_INSERT, &descriptor);
414 if (res != OK) {
415 ALOGE("addStreamDefaultEffect(): Failed to find effect descriptor matching uuid/type.");
416 return res;
417 }
418
419 // Only insert effects can be added dynamically as stream defaults.
420 if ((descriptor.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_INSERT) {
421 ALOGE("addStreamDefaultEffect(): Desired effect cannot be attached "
422 "as a stream default effect.");
423 return BAD_VALUE;
424 }
425
426 Mutex::Autolock _l(mLock);
427
428 // Find the EffectDescVector for the given stream type, or create a new one if necessary.
429 ssize_t index = mOutputStreams.indexOfKey(stream);
430 EffectDescVector *desc = NULL;
431 if (index < 0) {
432 // No effects for this stream type yet.
433 desc = new EffectDescVector();
434 mOutputStreams.add(stream, desc);
435 } else {
436 desc = mOutputStreams.valueAt(index);
437 }
438
439 // Create a new effect and add it to the vector.
440 res = AudioEffect::newEffectUniqueId(id);
441 if (res != OK) {
442 ALOGE("addStreamDefaultEffect(): failed to get new unique id.");
443 return res;
444 }
445 EffectDesc *effect = new EffectDesc(
446 descriptor.name, *type, opPackageName, *uuid, priority, *id);
447 desc->mEffects.add(effect);
448 // TODO(b/71813697): Support setting params as well.
449
450 // TODO(b/71814300): Retroactively attach to any existing streams of the given type.
451 // This requires tracking the stream type of each session id in addition to what is
452 // already being tracked.
453
454 return NO_ERROR;
455}
456
Ari Hausman-Cohen24628312018-08-13 15:01:09 -0700457status_t AudioPolicyEffects::removeSourceDefaultEffect(audio_unique_id_t id)
458{
459 if (id == AUDIO_UNIQUE_ID_ALLOCATE) {
460 // ALLOCATE is not a unique identifier, but rather a reserved value indicating
461 // a real id has not been assigned. For default effects, this value is only used
462 // by system-owned defaults from the loaded config, which cannot be removed.
463 return BAD_VALUE;
464 }
465
466 Mutex::Autolock _l(mLock);
467
468 // Check each source type.
469 size_t numSources = mInputSources.size();
470 for (size_t i = 0; i < numSources; ++i) {
471 // Check each effect for each source.
472 EffectDescVector* descVector = mInputSources[i];
473 for (auto desc = descVector->mEffects.begin(); desc != descVector->mEffects.end(); ++desc) {
474 if ((*desc)->mId == id) {
475 // Found it!
476 // TODO(b/71814300): Remove from any sources the effect was attached to.
477 descVector->mEffects.erase(desc);
478 // Handles are unique; there can only be one match, so return early.
479 return NO_ERROR;
480 }
481 }
482 }
483
484 // Effect wasn't found, so it's been trivially removed successfully.
485 return NO_ERROR;
486}
487
Ari Hausman-Cohen433722e2018-04-24 14:25:22 -0700488status_t AudioPolicyEffects::removeStreamDefaultEffect(audio_unique_id_t id)
489{
490 if (id == AUDIO_UNIQUE_ID_ALLOCATE) {
491 // ALLOCATE is not a unique identifier, but rather a reserved value indicating
492 // a real id has not been assigned. For default effects, this value is only used
493 // by system-owned defaults from the loaded config, which cannot be removed.
494 return BAD_VALUE;
495 }
496
497 Mutex::Autolock _l(mLock);
498
499 // Check each stream type.
500 size_t numStreams = mOutputStreams.size();
501 for (size_t i = 0; i < numStreams; ++i) {
502 // Check each effect for each stream.
503 EffectDescVector* descVector = mOutputStreams[i];
504 for (auto desc = descVector->mEffects.begin(); desc != descVector->mEffects.end(); ++desc) {
505 if ((*desc)->mId == id) {
506 // Found it!
507 // TODO(b/71814300): Remove from any streams the effect was attached to.
508 descVector->mEffects.erase(desc);
509 // Handles are unique; there can only be one match, so return early.
510 return NO_ERROR;
511 }
512 }
513 }
514
515 // Effect wasn't found, so it's been trivially removed successfully.
516 return NO_ERROR;
517}
bryant_liuba2b4392014-06-11 16:49:30 +0800518
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700519void AudioPolicyEffects::EffectVector::setProcessorEnabled(bool enabled)
bryant_liuba2b4392014-06-11 16:49:30 +0800520{
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700521 for (size_t i = 0; i < mEffects.size(); i++) {
522 mEffects.itemAt(i)->setEnabled(enabled);
bryant_liuba2b4392014-06-11 16:49:30 +0800523 }
524}
525
526
527// ----------------------------------------------------------------------------
528// Audio processing configuration
529// ----------------------------------------------------------------------------
530
531/*static*/ const char * const AudioPolicyEffects::kInputSourceNames[AUDIO_SOURCE_CNT -1] = {
532 MIC_SRC_TAG,
533 VOICE_UL_SRC_TAG,
534 VOICE_DL_SRC_TAG,
535 VOICE_CALL_SRC_TAG,
536 CAMCORDER_SRC_TAG,
537 VOICE_REC_SRC_TAG,
rago8a397d52015-12-02 11:27:57 -0800538 VOICE_COMM_SRC_TAG,
Eric Laurentae4b6ec2019-01-15 18:34:38 -0800539 UNPROCESSED_SRC_TAG,
540 VOICE_PERFORMANCE_SRC_TAG
bryant_liuba2b4392014-06-11 16:49:30 +0800541};
542
543// returns the audio_source_t enum corresponding to the input source name or
544// AUDIO_SOURCE_CNT is no match found
Eric Laurent8b1e80b2014-10-07 09:08:47 -0700545/*static*/ audio_source_t AudioPolicyEffects::inputSourceNameToEnum(const char *name)
bryant_liuba2b4392014-06-11 16:49:30 +0800546{
547 int i;
548 for (i = AUDIO_SOURCE_MIC; i < AUDIO_SOURCE_CNT; i++) {
549 if (strcmp(name, kInputSourceNames[i - AUDIO_SOURCE_MIC]) == 0) {
550 ALOGV("inputSourceNameToEnum found source %s %d", name, i);
551 break;
552 }
553 }
554 return (audio_source_t)i;
555}
556
Eric Laurent223fd5c2014-11-11 13:43:36 -0800557const char *AudioPolicyEffects::kStreamNames[AUDIO_STREAM_PUBLIC_CNT+1] = {
bryant_liuba2b4392014-06-11 16:49:30 +0800558 AUDIO_STREAM_DEFAULT_TAG,
559 AUDIO_STREAM_VOICE_CALL_TAG,
560 AUDIO_STREAM_SYSTEM_TAG,
561 AUDIO_STREAM_RING_TAG,
562 AUDIO_STREAM_MUSIC_TAG,
563 AUDIO_STREAM_ALARM_TAG,
564 AUDIO_STREAM_NOTIFICATION_TAG,
565 AUDIO_STREAM_BLUETOOTH_SCO_TAG,
566 AUDIO_STREAM_ENFORCED_AUDIBLE_TAG,
567 AUDIO_STREAM_DTMF_TAG,
Baekgyeong Kim47ea6712019-10-30 20:29:41 +0900568 AUDIO_STREAM_TTS_TAG,
569 AUDIO_STREAM_ASSISTANT_TAG
bryant_liuba2b4392014-06-11 16:49:30 +0800570};
571
572// returns the audio_stream_t enum corresponding to the output stream name or
Eric Laurent223fd5c2014-11-11 13:43:36 -0800573// AUDIO_STREAM_PUBLIC_CNT is no match found
bryant_liuba2b4392014-06-11 16:49:30 +0800574audio_stream_type_t AudioPolicyEffects::streamNameToEnum(const char *name)
575{
576 int i;
Eric Laurent223fd5c2014-11-11 13:43:36 -0800577 for (i = AUDIO_STREAM_DEFAULT; i < AUDIO_STREAM_PUBLIC_CNT; i++) {
bryant_liuba2b4392014-06-11 16:49:30 +0800578 if (strcmp(name, kStreamNames[i - AUDIO_STREAM_DEFAULT]) == 0) {
579 ALOGV("streamNameToEnum found stream %s %d", name, i);
580 break;
581 }
582 }
583 return (audio_stream_type_t)i;
584}
585
586// ----------------------------------------------------------------------------
587// Audio Effect Config parser
588// ----------------------------------------------------------------------------
589
Eric Laurent138ed172016-02-10 10:40:44 -0800590size_t AudioPolicyEffects::growParamSize(char **param,
bryant_liuba2b4392014-06-11 16:49:30 +0800591 size_t size,
592 size_t *curSize,
593 size_t *totSize)
594{
595 // *curSize is at least sizeof(effect_param_t) + 2 * sizeof(int)
596 size_t pos = ((*curSize - 1 ) / size + 1) * size;
597
598 if (pos + size > *totSize) {
599 while (pos + size > *totSize) {
600 *totSize += ((*totSize + 7) / 8) * 4;
601 }
George Burgess IV31225682018-02-12 11:08:38 -0800602 char *newParam = (char *)realloc(*param, *totSize);
603 if (newParam == NULL) {
Eric Laurent138ed172016-02-10 10:40:44 -0800604 ALOGE("%s realloc error for size %zu", __func__, *totSize);
605 return 0;
606 }
George Burgess IV31225682018-02-12 11:08:38 -0800607 *param = newParam;
bryant_liuba2b4392014-06-11 16:49:30 +0800608 }
609 *curSize = pos + size;
610 return pos;
611}
612
Eric Laurent138ed172016-02-10 10:40:44 -0800613
bryant_liuba2b4392014-06-11 16:49:30 +0800614size_t AudioPolicyEffects::readParamValue(cnode *node,
Eric Laurent138ed172016-02-10 10:40:44 -0800615 char **param,
bryant_liuba2b4392014-06-11 16:49:30 +0800616 size_t *curSize,
617 size_t *totSize)
618{
Eric Laurent138ed172016-02-10 10:40:44 -0800619 size_t len = 0;
620 size_t pos;
621
bryant_liuba2b4392014-06-11 16:49:30 +0800622 if (strncmp(node->name, SHORT_TAG, sizeof(SHORT_TAG) + 1) == 0) {
Eric Laurent138ed172016-02-10 10:40:44 -0800623 pos = growParamSize(param, sizeof(short), curSize, totSize);
624 if (pos == 0) {
625 goto exit;
bryant_liuba2b4392014-06-11 16:49:30 +0800626 }
Eric Laurent138ed172016-02-10 10:40:44 -0800627 *(short *)(*param + pos) = (short)atoi(node->value);
628 ALOGV("readParamValue() reading short %d", *(short *)(*param + pos));
629 len = sizeof(short);
630 } else if (strncmp(node->name, INT_TAG, sizeof(INT_TAG) + 1) == 0) {
631 pos = growParamSize(param, sizeof(int), curSize, totSize);
632 if (pos == 0) {
633 goto exit;
634 }
635 *(int *)(*param + pos) = atoi(node->value);
636 ALOGV("readParamValue() reading int %d", *(int *)(*param + pos));
637 len = sizeof(int);
638 } else if (strncmp(node->name, FLOAT_TAG, sizeof(FLOAT_TAG) + 1) == 0) {
639 pos = growParamSize(param, sizeof(float), curSize, totSize);
640 if (pos == 0) {
641 goto exit;
642 }
643 *(float *)(*param + pos) = (float)atof(node->value);
644 ALOGV("readParamValue() reading float %f",*(float *)(*param + pos));
645 len = sizeof(float);
646 } else if (strncmp(node->name, BOOL_TAG, sizeof(BOOL_TAG) + 1) == 0) {
647 pos = growParamSize(param, sizeof(bool), curSize, totSize);
648 if (pos == 0) {
649 goto exit;
650 }
651 if (strncmp(node->value, "true", strlen("true") + 1) == 0) {
652 *(bool *)(*param + pos) = true;
653 } else {
654 *(bool *)(*param + pos) = false;
655 }
656 ALOGV("readParamValue() reading bool %s",
657 *(bool *)(*param + pos) ? "true" : "false");
658 len = sizeof(bool);
bryant_liuba2b4392014-06-11 16:49:30 +0800659 } else if (strncmp(node->name, STRING_TAG, sizeof(STRING_TAG) + 1) == 0) {
Eric Laurent138ed172016-02-10 10:40:44 -0800660 len = strnlen(node->value, EFFECT_STRING_LEN_MAX);
bryant_liuba2b4392014-06-11 16:49:30 +0800661 if (*curSize + len + 1 > *totSize) {
662 *totSize = *curSize + len + 1;
Chih-Hung Hsieh03077682018-08-30 14:11:00 -0700663 char *newParam = (char *)realloc(*param, *totSize);
664 if (newParam == NULL) {
Eric Laurent138ed172016-02-10 10:40:44 -0800665 len = 0;
666 ALOGE("%s realloc error for string len %zu", __func__, *totSize);
667 goto exit;
668 }
Chih-Hung Hsieh03077682018-08-30 14:11:00 -0700669 *param = newParam;
bryant_liuba2b4392014-06-11 16:49:30 +0800670 }
Eric Laurent138ed172016-02-10 10:40:44 -0800671 strncpy(*param + *curSize, node->value, len);
bryant_liuba2b4392014-06-11 16:49:30 +0800672 *curSize += len;
Eric Laurent138ed172016-02-10 10:40:44 -0800673 (*param)[*curSize] = '\0';
674 ALOGV("readParamValue() reading string %s", *param + *curSize - len);
675 } else {
676 ALOGW("readParamValue() unknown param type %s", node->name);
bryant_liuba2b4392014-06-11 16:49:30 +0800677 }
Eric Laurent138ed172016-02-10 10:40:44 -0800678exit:
679 return len;
bryant_liuba2b4392014-06-11 16:49:30 +0800680}
681
682effect_param_t *AudioPolicyEffects::loadEffectParameter(cnode *root)
683{
684 cnode *param;
685 cnode *value;
686 size_t curSize = sizeof(effect_param_t);
687 size_t totSize = sizeof(effect_param_t) + 2 * sizeof(int);
688 effect_param_t *fx_param = (effect_param_t *)malloc(totSize);
689
Eric Laurent138ed172016-02-10 10:40:44 -0800690 if (fx_param == NULL) {
691 ALOGE("%s malloc error for effect structure of size %zu",
692 __func__, totSize);
693 return NULL;
694 }
695
bryant_liuba2b4392014-06-11 16:49:30 +0800696 param = config_find(root, PARAM_TAG);
697 value = config_find(root, VALUE_TAG);
698 if (param == NULL && value == NULL) {
699 // try to parse simple parameter form {int int}
700 param = root->first_child;
701 if (param != NULL) {
702 // Note: that a pair of random strings is read as 0 0
703 int *ptr = (int *)fx_param->data;
Eric Laurent138ed172016-02-10 10:40:44 -0800704#if LOG_NDEBUG == 0
bryant_liuba2b4392014-06-11 16:49:30 +0800705 int *ptr2 = (int *)((char *)param + sizeof(effect_param_t));
Eric Laurent138ed172016-02-10 10:40:44 -0800706 ALOGV("loadEffectParameter() ptr %p ptr2 %p", ptr, ptr2);
707#endif
bryant_liuba2b4392014-06-11 16:49:30 +0800708 *ptr++ = atoi(param->name);
709 *ptr = atoi(param->value);
710 fx_param->psize = sizeof(int);
711 fx_param->vsize = sizeof(int);
712 return fx_param;
713 }
714 }
715 if (param == NULL || value == NULL) {
Eric Laurent138ed172016-02-10 10:40:44 -0800716 ALOGW("loadEffectParameter() invalid parameter description %s",
717 root->name);
bryant_liuba2b4392014-06-11 16:49:30 +0800718 goto error;
719 }
720
721 fx_param->psize = 0;
722 param = param->first_child;
723 while (param) {
724 ALOGV("loadEffectParameter() reading param of type %s", param->name);
Eric Laurent138ed172016-02-10 10:40:44 -0800725 size_t size =
726 readParamValue(param, (char **)&fx_param, &curSize, &totSize);
bryant_liuba2b4392014-06-11 16:49:30 +0800727 if (size == 0) {
728 goto error;
729 }
730 fx_param->psize += size;
731 param = param->next;
732 }
733
734 // align start of value field on 32 bit boundary
735 curSize = ((curSize - 1 ) / sizeof(int) + 1) * sizeof(int);
736
737 fx_param->vsize = 0;
738 value = value->first_child;
739 while (value) {
740 ALOGV("loadEffectParameter() reading value of type %s", value->name);
Eric Laurent138ed172016-02-10 10:40:44 -0800741 size_t size =
742 readParamValue(value, (char **)&fx_param, &curSize, &totSize);
bryant_liuba2b4392014-06-11 16:49:30 +0800743 if (size == 0) {
744 goto error;
745 }
746 fx_param->vsize += size;
747 value = value->next;
748 }
749
750 return fx_param;
751
752error:
Eric Laurent138ed172016-02-10 10:40:44 -0800753 free(fx_param);
bryant_liuba2b4392014-06-11 16:49:30 +0800754 return NULL;
755}
756
757void AudioPolicyEffects::loadEffectParameters(cnode *root, Vector <effect_param_t *>& params)
758{
759 cnode *node = root->first_child;
760 while (node) {
761 ALOGV("loadEffectParameters() loading param %s", node->name);
762 effect_param_t *param = loadEffectParameter(node);
Eric Laurent138ed172016-02-10 10:40:44 -0800763 if (param != NULL) {
764 params.add(param);
bryant_liuba2b4392014-06-11 16:49:30 +0800765 }
bryant_liuba2b4392014-06-11 16:49:30 +0800766 node = node->next;
767 }
768}
769
770
771AudioPolicyEffects::EffectDescVector *AudioPolicyEffects::loadEffectConfig(
772 cnode *root,
773 const Vector <EffectDesc *>& effects)
774{
775 cnode *node = root->first_child;
776 if (node == NULL) {
777 ALOGW("loadInputSource() empty element %s", root->name);
778 return NULL;
779 }
780 EffectDescVector *desc = new EffectDescVector();
781 while (node) {
782 size_t i;
Eric Laurent138ed172016-02-10 10:40:44 -0800783
bryant_liuba2b4392014-06-11 16:49:30 +0800784 for (i = 0; i < effects.size(); i++) {
785 if (strncmp(effects[i]->mName, node->name, EFFECT_STRING_LEN_MAX) == 0) {
786 ALOGV("loadEffectConfig() found effect %s in list", node->name);
787 break;
788 }
789 }
790 if (i == effects.size()) {
791 ALOGV("loadEffectConfig() effect %s not in list", node->name);
792 node = node->next;
793 continue;
794 }
795 EffectDesc *effect = new EffectDesc(*effects[i]); // deep copy
796 loadEffectParameters(node, effect->mParams);
797 ALOGV("loadEffectConfig() adding effect %s uuid %08x",
798 effect->mName, effect->mUuid.timeLow);
799 desc->mEffects.add(effect);
800 node = node->next;
801 }
802 if (desc->mEffects.size() == 0) {
803 ALOGW("loadEffectConfig() no valid effects found in config %s", root->name);
804 delete desc;
805 return NULL;
806 }
807 return desc;
808}
809
810status_t AudioPolicyEffects::loadInputEffectConfigurations(cnode *root,
811 const Vector <EffectDesc *>& effects)
812{
813 cnode *node = config_find(root, PREPROCESSING_TAG);
814 if (node == NULL) {
815 return -ENOENT;
816 }
817 node = node->first_child;
818 while (node) {
819 audio_source_t source = inputSourceNameToEnum(node->name);
820 if (source == AUDIO_SOURCE_CNT) {
821 ALOGW("loadInputSources() invalid input source %s", node->name);
822 node = node->next;
823 continue;
824 }
825 ALOGV("loadInputSources() loading input source %s", node->name);
826 EffectDescVector *desc = loadEffectConfig(node, effects);
827 if (desc == NULL) {
828 node = node->next;
829 continue;
830 }
831 mInputSources.add(source, desc);
832 node = node->next;
833 }
834 return NO_ERROR;
835}
836
837status_t AudioPolicyEffects::loadStreamEffectConfigurations(cnode *root,
838 const Vector <EffectDesc *>& effects)
839{
840 cnode *node = config_find(root, OUTPUT_SESSION_PROCESSING_TAG);
841 if (node == NULL) {
842 return -ENOENT;
843 }
844 node = node->first_child;
845 while (node) {
846 audio_stream_type_t stream = streamNameToEnum(node->name);
Eric Laurent223fd5c2014-11-11 13:43:36 -0800847 if (stream == AUDIO_STREAM_PUBLIC_CNT) {
bryant_liuba2b4392014-06-11 16:49:30 +0800848 ALOGW("loadStreamEffectConfigurations() invalid output stream %s", node->name);
849 node = node->next;
850 continue;
851 }
852 ALOGV("loadStreamEffectConfigurations() loading output stream %s", node->name);
853 EffectDescVector *desc = loadEffectConfig(node, effects);
854 if (desc == NULL) {
855 node = node->next;
856 continue;
857 }
858 mOutputStreams.add(stream, desc);
859 node = node->next;
860 }
861 return NO_ERROR;
862}
863
864AudioPolicyEffects::EffectDesc *AudioPolicyEffects::loadEffect(cnode *root)
865{
866 cnode *node = config_find(root, UUID_TAG);
867 if (node == NULL) {
868 return NULL;
869 }
870 effect_uuid_t uuid;
871 if (AudioEffect::stringToGuid(node->value, &uuid) != NO_ERROR) {
872 ALOGW("loadEffect() invalid uuid %s", node->value);
873 return NULL;
874 }
875 return new EffectDesc(root->name, uuid);
876}
877
878status_t AudioPolicyEffects::loadEffects(cnode *root, Vector <EffectDesc *>& effects)
879{
880 cnode *node = config_find(root, EFFECTS_TAG);
881 if (node == NULL) {
882 return -ENOENT;
883 }
884 node = node->first_child;
885 while (node) {
886 ALOGV("loadEffects() loading effect %s", node->name);
887 EffectDesc *effect = loadEffect(node);
888 if (effect == NULL) {
889 node = node->next;
890 continue;
891 }
892 effects.add(effect);
893 node = node->next;
894 }
895 return NO_ERROR;
896}
897
Kevin Rocard4fb615c2017-06-26 10:28:13 -0700898status_t AudioPolicyEffects::loadAudioEffectXmlConfig() {
899 auto result = effectsConfig::parse();
900 if (result.parsedConfig == nullptr) {
901 return -ENOENT;
902 }
903
904 auto loadProcessingChain = [](auto& processingChain, auto& streams) {
905 for (auto& stream : processingChain) {
906 auto effectDescs = std::make_unique<EffectDescVector>();
907 for (auto& effect : stream.effects) {
908 effectDescs->mEffects.add(
909 new EffectDesc{effect.get().name.c_str(), effect.get().uuid});
910 }
911 streams.add(stream.type, effectDescs.release());
912 }
913 };
François Gaffiee8e0e7a2020-01-07 15:16:14 +0100914
915 auto loadDeviceProcessingChain = [](auto &processingChain, auto& devicesEffects) {
916 for (auto& deviceProcess : processingChain) {
917
918 auto effectDescs = std::make_unique<EffectDescVector>();
919 for (auto& effect : deviceProcess.effects) {
920 effectDescs->mEffects.add(
921 new EffectDesc{effect.get().name.c_str(), effect.get().uuid});
922 }
923 auto deviceEffects = std::make_unique<DeviceEffects>(
924 std::move(effectDescs), deviceProcess.type, deviceProcess.address);
925 devicesEffects.emplace(deviceProcess.address, std::move(deviceEffects));
926 }
927 };
928
Kevin Rocard4fb615c2017-06-26 10:28:13 -0700929 loadProcessingChain(result.parsedConfig->preprocess, mInputSources);
930 loadProcessingChain(result.parsedConfig->postprocess, mOutputStreams);
Mikhail Naganov12b716c2020-04-30 22:37:43 +0000931 {
932 Mutex::Autolock _l(mLock);
933 loadDeviceProcessingChain(result.parsedConfig->deviceprocess, mDeviceEffects);
934 }
Kevin Rocard4fb615c2017-06-26 10:28:13 -0700935 // Casting from ssize_t to status_t is probably safe, there should not be more than 2^31 errors
936 return result.nbSkippedElement;
937}
938
bryant_liuba2b4392014-06-11 16:49:30 +0800939status_t AudioPolicyEffects::loadAudioEffectConfig(const char *path)
940{
941 cnode *root;
942 char *data;
943
944 data = (char *)load_file(path, NULL);
945 if (data == NULL) {
946 return -ENODEV;
947 }
948 root = config_node("", "");
949 config_load(root, data);
950
951 Vector <EffectDesc *> effects;
952 loadEffects(root, effects);
953 loadInputEffectConfigurations(root, effects);
954 loadStreamEffectConfigurations(root, effects);
955
Eric Laurent182c2f52015-01-15 14:29:19 -0800956 for (size_t i = 0; i < effects.size(); i++) {
957 delete effects[i];
958 }
959
bryant_liuba2b4392014-06-11 16:49:30 +0800960 config_free(root);
961 free(root);
962 free(data);
963
964 return NO_ERROR;
965}
966
François Gaffiee8e0e7a2020-01-07 15:16:14 +0100967void AudioPolicyEffects::initDefaultDeviceEffects()
968{
969 Mutex::Autolock _l(mLock);
970 for (const auto& deviceEffectsIter : mDeviceEffects) {
971 const auto& deviceEffects = deviceEffectsIter.second;
972 for (const auto& effectDesc : deviceEffects->mEffectDescriptors->mEffects) {
973 auto fx = std::make_unique<AudioEffect>(
974 EFFECT_UUID_NULL, String16("android"), &effectDesc->mUuid, 0, nullptr,
975 nullptr, AUDIO_SESSION_DEVICE, AUDIO_IO_HANDLE_NONE,
976 AudioDeviceTypeAddr{deviceEffects->getDeviceType(),
977 deviceEffects->getDeviceAddress()});
978 status_t status = fx->initCheck();
979 if (status != NO_ERROR && status != ALREADY_EXISTS) {
980 ALOGE("%s(): failed to create Fx %s on port type=%d address=%s", __func__,
981 effectDesc->mName, deviceEffects->getDeviceType(),
982 deviceEffects->getDeviceAddress().c_str());
983 // fx goes out of scope and strong ref on AudioEffect is released
984 continue;
985 }
986 fx->setEnabled(true);
987 ALOGV("%s(): create Fx %s added on port type=%d address=%s", __func__,
988 effectDesc->mName, deviceEffects->getDeviceType(),
989 deviceEffects->getDeviceAddress().c_str());
990 deviceEffects->mEffects.push_back(std::move(fx));
991 }
992 }
993}
bryant_liuba2b4392014-06-11 16:49:30 +0800994
Mikhail Naganov1b2a7942017-12-08 10:18:09 -0800995} // namespace android