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