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