blob: bd0d7fbc2a570809a54f112d61c055d255519d5b [file] [log] [blame]
Eric Laurentb82e6b72019-11-22 17:25:04 -08001/*
2**
3** Copyright 2019, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18
19#define LOG_TAG "AudioFlinger::DeviceEffectManager"
20//#define LOG_NDEBUG 0
21
22#include <utils/Log.h>
23#include <audio_utils/primitives.h>
24
25#include "AudioFlinger.h"
26#include <media/audiohal/EffectsFactoryHalInterface.h>
27
28// ----------------------------------------------------------------------------
29
30
31namespace android {
32
Shunkai Yao489c5a92022-12-02 05:35:41 +000033using media::AudioHalVersion;
Ytai Ben-Tsvi9cd89812020-07-01 17:12:06 -070034using media::IEffectClient;
35
Eric Laurentb82e6b72019-11-22 17:25:04 -080036void AudioFlinger::DeviceEffectManager::onCreateAudioPatch(audio_patch_handle_t handle,
37 const PatchPanel::Patch& patch) {
38 ALOGV("%s handle %d mHalHandle %d device sink %08x",
39 __func__, handle, patch.mHalHandle,
40 patch.mAudioPatch.num_sinks > 0 ? patch.mAudioPatch.sinks[0].ext.device.type : 0);
41 Mutex::Autolock _l(mLock);
42 for (auto& effect : mDeviceEffects) {
43 status_t status = effect.second->onCreatePatch(handle, patch);
44 ALOGV("%s Effect onCreatePatch status %d", __func__, status);
45 ALOGW_IF(status == BAD_VALUE, "%s onCreatePatch error %d", __func__, status);
46 }
47}
48
Eric Laurentb82e6b72019-11-22 17:25:04 -080049void AudioFlinger::DeviceEffectManager::onReleaseAudioPatch(audio_patch_handle_t handle) {
50 ALOGV("%s", __func__);
51 Mutex::Autolock _l(mLock);
52 for (auto& effect : mDeviceEffects) {
53 effect.second->onReleasePatch(handle);
54 }
55}
56
57// DeviceEffectManager::createEffect_l() must be called with AudioFlinger::mLock held
58sp<AudioFlinger::EffectHandle> AudioFlinger::DeviceEffectManager::createEffect_l(
59 effect_descriptor_t *descriptor,
60 const AudioDeviceTypeAddr& device,
61 const sp<AudioFlinger::Client>& client,
62 const sp<IEffectClient>& effectClient,
63 const std::map<audio_patch_handle_t, PatchPanel::Patch>& patches,
64 int *enabled,
Eric Laurent2fe0acd2020-03-13 14:30:46 -070065 status_t *status,
Eric Laurentde8caf42021-08-11 17:19:25 +020066 bool probe,
67 bool notifyFramesProcessed) {
Eric Laurentb82e6b72019-11-22 17:25:04 -080068 sp<DeviceEffectProxy> effect;
69 sp<EffectHandle> handle;
70 status_t lStatus;
71
72 lStatus = checkEffectCompatibility(descriptor);
Eric Laurent2fe0acd2020-03-13 14:30:46 -070073 if (probe || lStatus != NO_ERROR) {
Eric Laurentb82e6b72019-11-22 17:25:04 -080074 *status = lStatus;
75 return handle;
76 }
77
78 {
79 Mutex::Autolock _l(mLock);
80 auto iter = mDeviceEffects.find(device);
81 if (iter != mDeviceEffects.end()) {
82 effect = iter->second;
83 } else {
84 effect = new DeviceEffectProxy(device, mMyCallback,
Eric Laurentde8caf42021-08-11 17:19:25 +020085 descriptor, mAudioFlinger.nextUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT),
86 notifyFramesProcessed);
Eric Laurentb82e6b72019-11-22 17:25:04 -080087 }
88 // create effect handle and connect it to effect module
Eric Laurentde8caf42021-08-11 17:19:25 +020089 handle = new EffectHandle(effect, client, effectClient, 0 /*priority*/,
90 notifyFramesProcessed);
Eric Laurentb82e6b72019-11-22 17:25:04 -080091 lStatus = handle->initCheck();
92 if (lStatus == NO_ERROR) {
93 lStatus = effect->addHandle(handle.get());
94 if (lStatus == NO_ERROR) {
Ram Mohan M2a05df22022-08-28 11:46:23 +053095 lStatus = effect->init(patches);
96 if (lStatus == NAME_NOT_FOUND) {
97 lStatus = NO_ERROR;
98 }
99 if (lStatus == NO_ERROR || lStatus == ALREADY_EXISTS) {
100 mDeviceEffects.emplace(device, effect);
101 }
Eric Laurentb82e6b72019-11-22 17:25:04 -0800102 }
103 }
104 }
Vlad Popa5161f8a2022-10-10 16:17:20 +0200105 if (enabled != nullptr) {
Eric Laurentb82e6b72019-11-22 17:25:04 -0800106 *enabled = (int)effect->isEnabled();
107 }
108 *status = lStatus;
109 return handle;
110}
111
112status_t AudioFlinger::DeviceEffectManager::checkEffectCompatibility(
113 const effect_descriptor_t *desc) {
Eric Laurent9289bde2020-08-18 12:49:17 -0700114 sp<EffectsFactoryHalInterface> effectsFactory = mAudioFlinger.getEffectsFactory();
115 if (effectsFactory == nullptr) {
116 return BAD_VALUE;
117 }
Eric Laurentb82e6b72019-11-22 17:25:04 -0800118
Shunkai Yao489c5a92022-12-02 05:35:41 +0000119 static AudioHalVersion sMinDeviceEffectHalVersion;
120 sMinDeviceEffectHalVersion.type = AudioHalVersion::Type::HIDL;
121 sMinDeviceEffectHalVersion.major = 6;
122 sMinDeviceEffectHalVersion.minor = 0;
123 AudioHalVersion halVersion = effectsFactory->getHalVersion();
Eric Laurent9289bde2020-08-18 12:49:17 -0700124
Shunkai Yao489c5a92022-12-02 05:35:41 +0000125 // We can trust AIDL generated AudioHalVersion comparison operator (based on std::tie) as long
126 // as the type, major and minor sequence doesn't change in the definition.
Eric Laurent9289bde2020-08-18 12:49:17 -0700127 if (((desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_PRE_PROC
128 && (desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_POST_PROC)
129 || halVersion < sMinDeviceEffectHalVersion) {
Shunkai Yao489c5a92022-12-02 05:35:41 +0000130 ALOGW("%s() non pre/post processing device effect %s or incompatible API version %s",
131 __func__, desc->name, halVersion.toString().c_str());
Eric Laurentb82e6b72019-11-22 17:25:04 -0800132 return BAD_VALUE;
133 }
134
135 return NO_ERROR;
136}
137
138status_t AudioFlinger::DeviceEffectManager::createEffectHal(
139 const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t deviceId,
140 sp<EffectHalInterface> *effect) {
141 status_t status = NO_INIT;
142 sp<EffectsFactoryHalInterface> effectsFactory = mAudioFlinger.getEffectsFactory();
143 if (effectsFactory != 0) {
144 status = effectsFactory->createEffect(
145 pEffectUuid, sessionId, AUDIO_IO_HANDLE_NONE, deviceId, effect);
146 }
147 return status;
148}
149
150void AudioFlinger::DeviceEffectManager::dump(int fd) {
151 const bool locked = dumpTryLock(mLock);
152 if (!locked) {
153 String8 result("DeviceEffectManager may be deadlocked\n");
154 write(fd, result.string(), result.size());
155 }
156
Phil Burk651d0a52020-05-08 14:00:58 -0700157 String8 heading("\nDevice Effects:\n");
158 write(fd, heading.string(), heading.size());
Eric Laurentb82e6b72019-11-22 17:25:04 -0800159 for (const auto& iter : mDeviceEffects) {
160 String8 outStr;
161 outStr.appendFormat("%*sEffect for device %s address %s:\n", 2, "",
162 ::android::toString(iter.first.mType).c_str(), iter.first.getAddress());
163 write(fd, outStr.string(), outStr.size());
164 iter.second->dump(fd, 4);
165 }
166
167 if (locked) {
168 mLock.unlock();
169 }
170}
171
172
173size_t AudioFlinger::DeviceEffectManager::removeEffect(const sp<DeviceEffectProxy>& effect)
174{
175 Mutex::Autolock _l(mLock);
176 mDeviceEffects.erase(effect->device());
177 return mDeviceEffects.size();
178}
179
180bool AudioFlinger::DeviceEffectManagerCallback::disconnectEffectHandle(
181 EffectHandle *handle, bool unpinIfLast) {
182 sp<EffectBase> effectBase = handle->effect().promote();
183 if (effectBase == nullptr) {
184 return false;
185 }
186
187 sp<DeviceEffectProxy> effect = effectBase->asDeviceEffectProxy();
188 if (effect == nullptr) {
189 return false;
190 }
191 // restore suspended effects if the disconnected handle was enabled and the last one.
192 bool remove = (effect->removeHandle(handle) == 0) && (!effect->isPinned() || unpinIfLast);
193 if (remove) {
194 mManager.removeEffect(effect);
195 if (handle->enabled()) {
196 effectBase->checkSuspendOnEffectEnabled(false, false /*threadLocked*/);
197 }
198 }
199 return true;
200}
201
Eric Laurentb82e6b72019-11-22 17:25:04 -0800202} // namespace android