blob: 4f3ed0a71d3b13e7fe508a749254dd7b8cad85fd [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
Ytai Ben-Tsvi9cd89812020-07-01 17:12:06 -070033using media::IEffectClient;
34
Eric Laurentb82e6b72019-11-22 17:25:04 -080035void AudioFlinger::DeviceEffectManager::createAudioPatch(audio_patch_handle_t handle,
36 const PatchPanel::Patch& patch) {
37 ALOGV("%s handle %d mHalHandle %d num sinks %d device sink %08x",
38 __func__, handle, patch.mHalHandle,
39 patch.mAudioPatch.num_sinks,
40 patch.mAudioPatch.num_sinks > 0 ? patch.mAudioPatch.sinks[0].ext.device.type : 0);
41
42 mCommandThread->createAudioPatchCommand(handle, patch);
43}
44
45void AudioFlinger::DeviceEffectManager::onCreateAudioPatch(audio_patch_handle_t handle,
46 const PatchPanel::Patch& patch) {
47 ALOGV("%s handle %d mHalHandle %d device sink %08x",
48 __func__, handle, patch.mHalHandle,
49 patch.mAudioPatch.num_sinks > 0 ? patch.mAudioPatch.sinks[0].ext.device.type : 0);
50 Mutex::Autolock _l(mLock);
51 for (auto& effect : mDeviceEffects) {
52 status_t status = effect.second->onCreatePatch(handle, patch);
53 ALOGV("%s Effect onCreatePatch status %d", __func__, status);
54 ALOGW_IF(status == BAD_VALUE, "%s onCreatePatch error %d", __func__, status);
55 }
56}
57
58void AudioFlinger::DeviceEffectManager::releaseAudioPatch(audio_patch_handle_t handle) {
59 ALOGV("%s", __func__);
60 mCommandThread->releaseAudioPatchCommand(handle);
61}
62
63void AudioFlinger::DeviceEffectManager::onReleaseAudioPatch(audio_patch_handle_t handle) {
64 ALOGV("%s", __func__);
65 Mutex::Autolock _l(mLock);
66 for (auto& effect : mDeviceEffects) {
67 effect.second->onReleasePatch(handle);
68 }
69}
70
71// DeviceEffectManager::createEffect_l() must be called with AudioFlinger::mLock held
72sp<AudioFlinger::EffectHandle> AudioFlinger::DeviceEffectManager::createEffect_l(
73 effect_descriptor_t *descriptor,
74 const AudioDeviceTypeAddr& device,
75 const sp<AudioFlinger::Client>& client,
76 const sp<IEffectClient>& effectClient,
77 const std::map<audio_patch_handle_t, PatchPanel::Patch>& patches,
78 int *enabled,
Eric Laurent2fe0acd2020-03-13 14:30:46 -070079 status_t *status,
Eric Laurentde8caf42021-08-11 17:19:25 +020080 bool probe,
81 bool notifyFramesProcessed) {
Eric Laurentb82e6b72019-11-22 17:25:04 -080082 sp<DeviceEffectProxy> effect;
83 sp<EffectHandle> handle;
84 status_t lStatus;
85
86 lStatus = checkEffectCompatibility(descriptor);
Eric Laurent2fe0acd2020-03-13 14:30:46 -070087 if (probe || lStatus != NO_ERROR) {
Eric Laurentb82e6b72019-11-22 17:25:04 -080088 *status = lStatus;
89 return handle;
90 }
91
92 {
93 Mutex::Autolock _l(mLock);
94 auto iter = mDeviceEffects.find(device);
95 if (iter != mDeviceEffects.end()) {
96 effect = iter->second;
97 } else {
98 effect = new DeviceEffectProxy(device, mMyCallback,
Eric Laurentde8caf42021-08-11 17:19:25 +020099 descriptor, mAudioFlinger.nextUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT),
100 notifyFramesProcessed);
Eric Laurentb82e6b72019-11-22 17:25:04 -0800101 }
102 // create effect handle and connect it to effect module
Eric Laurentde8caf42021-08-11 17:19:25 +0200103 handle = new EffectHandle(effect, client, effectClient, 0 /*priority*/,
104 notifyFramesProcessed);
Eric Laurentb82e6b72019-11-22 17:25:04 -0800105 lStatus = handle->initCheck();
106 if (lStatus == NO_ERROR) {
107 lStatus = effect->addHandle(handle.get());
108 if (lStatus == NO_ERROR) {
Ram Mohan M2a05df22022-08-28 11:46:23 +0530109 lStatus = effect->init(patches);
110 if (lStatus == NAME_NOT_FOUND) {
111 lStatus = NO_ERROR;
112 }
113 if (lStatus == NO_ERROR || lStatus == ALREADY_EXISTS) {
114 mDeviceEffects.emplace(device, effect);
115 }
Eric Laurentb82e6b72019-11-22 17:25:04 -0800116 }
117 }
118 }
119 if (enabled != NULL) {
120 *enabled = (int)effect->isEnabled();
121 }
122 *status = lStatus;
123 return handle;
124}
125
126status_t AudioFlinger::DeviceEffectManager::checkEffectCompatibility(
127 const effect_descriptor_t *desc) {
Eric Laurent9289bde2020-08-18 12:49:17 -0700128 sp<EffectsFactoryHalInterface> effectsFactory = mAudioFlinger.getEffectsFactory();
129 if (effectsFactory == nullptr) {
130 return BAD_VALUE;
131 }
Eric Laurentb82e6b72019-11-22 17:25:04 -0800132
Eric Laurent9289bde2020-08-18 12:49:17 -0700133 static const float sMinDeviceEffectHalVersion = 6.0;
134 float halVersion = effectsFactory->getHalVersion();
135
136 if (((desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_PRE_PROC
137 && (desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_POST_PROC)
138 || halVersion < sMinDeviceEffectHalVersion) {
139 ALOGW("%s() non pre/post processing device effect %s or incompatible API version %f",
140 __func__, desc->name, halVersion);
Eric Laurentb82e6b72019-11-22 17:25:04 -0800141 return BAD_VALUE;
142 }
143
144 return NO_ERROR;
145}
146
147status_t AudioFlinger::DeviceEffectManager::createEffectHal(
148 const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t deviceId,
149 sp<EffectHalInterface> *effect) {
150 status_t status = NO_INIT;
151 sp<EffectsFactoryHalInterface> effectsFactory = mAudioFlinger.getEffectsFactory();
152 if (effectsFactory != 0) {
153 status = effectsFactory->createEffect(
154 pEffectUuid, sessionId, AUDIO_IO_HANDLE_NONE, deviceId, effect);
155 }
156 return status;
157}
158
159void AudioFlinger::DeviceEffectManager::dump(int fd) {
160 const bool locked = dumpTryLock(mLock);
161 if (!locked) {
162 String8 result("DeviceEffectManager may be deadlocked\n");
163 write(fd, result.string(), result.size());
164 }
165
Phil Burk651d0a52020-05-08 14:00:58 -0700166 String8 heading("\nDevice Effects:\n");
167 write(fd, heading.string(), heading.size());
Eric Laurentb82e6b72019-11-22 17:25:04 -0800168 for (const auto& iter : mDeviceEffects) {
169 String8 outStr;
170 outStr.appendFormat("%*sEffect for device %s address %s:\n", 2, "",
171 ::android::toString(iter.first.mType).c_str(), iter.first.getAddress());
172 write(fd, outStr.string(), outStr.size());
173 iter.second->dump(fd, 4);
174 }
175
176 if (locked) {
177 mLock.unlock();
178 }
179}
180
181
182size_t AudioFlinger::DeviceEffectManager::removeEffect(const sp<DeviceEffectProxy>& effect)
183{
184 Mutex::Autolock _l(mLock);
185 mDeviceEffects.erase(effect->device());
186 return mDeviceEffects.size();
187}
188
189bool AudioFlinger::DeviceEffectManagerCallback::disconnectEffectHandle(
190 EffectHandle *handle, bool unpinIfLast) {
191 sp<EffectBase> effectBase = handle->effect().promote();
192 if (effectBase == nullptr) {
193 return false;
194 }
195
196 sp<DeviceEffectProxy> effect = effectBase->asDeviceEffectProxy();
197 if (effect == nullptr) {
198 return false;
199 }
200 // restore suspended effects if the disconnected handle was enabled and the last one.
201 bool remove = (effect->removeHandle(handle) == 0) && (!effect->isPinned() || unpinIfLast);
202 if (remove) {
203 mManager.removeEffect(effect);
204 if (handle->enabled()) {
205 effectBase->checkSuspendOnEffectEnabled(false, false /*threadLocked*/);
206 }
207 }
208 return true;
209}
210
211// ----------- DeviceEffectManager::CommandThread implementation ----------
212
213
214AudioFlinger::DeviceEffectManager::CommandThread::~CommandThread()
215{
216 Mutex::Autolock _l(mLock);
217 mCommands.clear();
218}
219
220void AudioFlinger::DeviceEffectManager::CommandThread::onFirstRef()
221{
222 run("DeviceEffectManage_CommandThread", ANDROID_PRIORITY_AUDIO);
223}
224
225bool AudioFlinger::DeviceEffectManager::CommandThread::threadLoop()
226{
227 mLock.lock();
228 while (!exitPending())
229 {
230 while (!mCommands.empty() && !exitPending()) {
231 sp<Command> command = mCommands.front();
232 mCommands.pop_front();
233 mLock.unlock();
234
235 switch (command->mCommand) {
236 case CREATE_AUDIO_PATCH: {
237 CreateAudioPatchData *data = (CreateAudioPatchData *)command->mData.get();
238 ALOGV("CommandThread() processing create audio patch handle %d", data->mHandle);
239 mManager.onCreateAudioPatch(data->mHandle, data->mPatch);
240 } break;
241 case RELEASE_AUDIO_PATCH: {
242 ReleaseAudioPatchData *data = (ReleaseAudioPatchData *)command->mData.get();
243 ALOGV("CommandThread() processing release audio patch handle %d", data->mHandle);
244 mManager.onReleaseAudioPatch(data->mHandle);
245 } break;
246 default:
247 ALOGW("CommandThread() unknown command %d", command->mCommand);
248 }
249 mLock.lock();
250 }
251
252 // At this stage we have either an empty command queue or the first command in the queue
253 // has a finite delay. So unless we are exiting it is safe to wait.
254 if (!exitPending()) {
255 ALOGV("CommandThread() going to sleep");
256 mWaitWorkCV.wait(mLock);
257 }
258 }
259 mLock.unlock();
260 return false;
261}
262
263void AudioFlinger::DeviceEffectManager::CommandThread::sendCommand(sp<Command> command) {
264 Mutex::Autolock _l(mLock);
265 mCommands.push_back(command);
266 mWaitWorkCV.signal();
267}
268
269void AudioFlinger::DeviceEffectManager::CommandThread::createAudioPatchCommand(
270 audio_patch_handle_t handle, const PatchPanel::Patch& patch)
271{
272 sp<Command> command = new Command(CREATE_AUDIO_PATCH, new CreateAudioPatchData(handle, patch));
273 ALOGV("CommandThread() adding create patch handle %d mHalHandle %d.", handle, patch.mHalHandle);
274 sendCommand(command);
275}
276
277void AudioFlinger::DeviceEffectManager::CommandThread::releaseAudioPatchCommand(
278 audio_patch_handle_t handle)
279{
280 sp<Command> command = new Command(RELEASE_AUDIO_PATCH, new ReleaseAudioPatchData(handle));
281 ALOGV("CommandThread() adding release patch");
282 sendCommand(command);
283}
284
285void AudioFlinger::DeviceEffectManager::CommandThread::exit()
286{
287 ALOGV("CommandThread::exit");
288 {
289 AutoMutex _l(mLock);
290 requestExit();
291 mWaitWorkCV.signal();
292 }
293 // Note that we can call it from the thread loop if all other references have been released
294 // but it will safely return WOULD_BLOCK in this case
295 requestExitAndWait();
296}
297
298} // namespace android