1 /*
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
31 namespace android {
32
createAudioPatch(audio_patch_handle_t handle,const PatchPanel::Patch & patch)33 void 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
onCreateAudioPatch(audio_patch_handle_t handle,const PatchPanel::Patch & patch)43 void 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
releaseAudioPatch(audio_patch_handle_t handle)56 void AudioFlinger::DeviceEffectManager::releaseAudioPatch(audio_patch_handle_t handle) {
57 ALOGV("%s", __func__);
58 mCommandThread->releaseAudioPatchCommand(handle);
59 }
60
onReleaseAudioPatch(audio_patch_handle_t handle)61 void 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
createEffect_l(effect_descriptor_t * descriptor,const AudioDeviceTypeAddr & device,const sp<AudioFlinger::Client> & client,const sp<IEffectClient> & effectClient,const std::map<audio_patch_handle_t,PatchPanel::Patch> & patches,int * enabled,status_t * status)70 sp<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,
77 status_t *status) {
78 sp<DeviceEffectProxy> effect;
79 sp<EffectHandle> handle;
80 status_t lStatus;
81
82 lStatus = checkEffectCompatibility(descriptor);
83 if (lStatus != NO_ERROR) {
84 *status = lStatus;
85 return handle;
86 }
87
88 {
89 Mutex::Autolock _l(mLock);
90 auto iter = mDeviceEffects.find(device);
91 if (iter != mDeviceEffects.end()) {
92 effect = iter->second;
93 } else {
94 effect = new DeviceEffectProxy(device, mMyCallback,
95 descriptor, mAudioFlinger.nextUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT));
96 }
97 // create effect handle and connect it to effect module
98 handle = new EffectHandle(effect, client, effectClient, 0 /*priority*/);
99 lStatus = handle->initCheck();
100 if (lStatus == NO_ERROR) {
101 lStatus = effect->addHandle(handle.get());
102 if (lStatus == NO_ERROR) {
103 effect->init(patches);
104 mDeviceEffects.emplace(device, effect);
105 }
106 }
107 }
108 if (enabled != NULL) {
109 *enabled = (int)effect->isEnabled();
110 }
111 *status = lStatus;
112 return handle;
113 }
114
checkEffectCompatibility(const effect_descriptor_t * desc)115 status_t AudioFlinger::DeviceEffectManager::checkEffectCompatibility(
116 const effect_descriptor_t *desc) {
117
118 if ((desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_PRE_PROC
119 && (desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_POST_PROC) {
120 ALOGW("%s() non pre/post processing device effect %s", __func__, desc->name);
121 return BAD_VALUE;
122 }
123
124 return NO_ERROR;
125 }
126
createEffectHal(const effect_uuid_t * pEffectUuid,int32_t sessionId,int32_t deviceId,sp<EffectHalInterface> * effect)127 status_t AudioFlinger::DeviceEffectManager::createEffectHal(
128 const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t deviceId,
129 sp<EffectHalInterface> *effect) {
130 status_t status = NO_INIT;
131 sp<EffectsFactoryHalInterface> effectsFactory = mAudioFlinger.getEffectsFactory();
132 if (effectsFactory != 0) {
133 status = effectsFactory->createEffect(
134 pEffectUuid, sessionId, AUDIO_IO_HANDLE_NONE, deviceId, effect);
135 }
136 return status;
137 }
138
dump(int fd)139 void AudioFlinger::DeviceEffectManager::dump(int fd) {
140 const bool locked = dumpTryLock(mLock);
141 if (!locked) {
142 String8 result("DeviceEffectManager may be deadlocked\n");
143 write(fd, result.string(), result.size());
144 }
145
146 write(fd, "\nDevice Effects:\n", sizeof("\nDevice Effects:\n"));
147 for (const auto& iter : mDeviceEffects) {
148 String8 outStr;
149 outStr.appendFormat("%*sEffect for device %s address %s:\n", 2, "",
150 ::android::toString(iter.first.mType).c_str(), iter.first.getAddress());
151 write(fd, outStr.string(), outStr.size());
152 iter.second->dump(fd, 4);
153 }
154
155 if (locked) {
156 mLock.unlock();
157 }
158 }
159
160
removeEffect(const sp<DeviceEffectProxy> & effect)161 size_t AudioFlinger::DeviceEffectManager::removeEffect(const sp<DeviceEffectProxy>& effect)
162 {
163 Mutex::Autolock _l(mLock);
164 mDeviceEffects.erase(effect->device());
165 return mDeviceEffects.size();
166 }
167
disconnectEffectHandle(EffectHandle * handle,bool unpinIfLast)168 bool AudioFlinger::DeviceEffectManagerCallback::disconnectEffectHandle(
169 EffectHandle *handle, bool unpinIfLast) {
170 sp<EffectBase> effectBase = handle->effect().promote();
171 if (effectBase == nullptr) {
172 return false;
173 }
174
175 sp<DeviceEffectProxy> effect = effectBase->asDeviceEffectProxy();
176 if (effect == nullptr) {
177 return false;
178 }
179 // restore suspended effects if the disconnected handle was enabled and the last one.
180 bool remove = (effect->removeHandle(handle) == 0) && (!effect->isPinned() || unpinIfLast);
181 if (remove) {
182 mManager.removeEffect(effect);
183 if (handle->enabled()) {
184 effectBase->checkSuspendOnEffectEnabled(false, false /*threadLocked*/);
185 }
186 }
187 return true;
188 }
189
190 // ----------- DeviceEffectManager::CommandThread implementation ----------
191
192
~CommandThread()193 AudioFlinger::DeviceEffectManager::CommandThread::~CommandThread()
194 {
195 Mutex::Autolock _l(mLock);
196 mCommands.clear();
197 }
198
onFirstRef()199 void AudioFlinger::DeviceEffectManager::CommandThread::onFirstRef()
200 {
201 run("DeviceEffectManage_CommandThread", ANDROID_PRIORITY_AUDIO);
202 }
203
threadLoop()204 bool AudioFlinger::DeviceEffectManager::CommandThread::threadLoop()
205 {
206 mLock.lock();
207 while (!exitPending())
208 {
209 while (!mCommands.empty() && !exitPending()) {
210 sp<Command> command = mCommands.front();
211 mCommands.pop_front();
212 mLock.unlock();
213
214 switch (command->mCommand) {
215 case CREATE_AUDIO_PATCH: {
216 CreateAudioPatchData *data = (CreateAudioPatchData *)command->mData.get();
217 ALOGV("CommandThread() processing create audio patch handle %d", data->mHandle);
218 mManager.onCreateAudioPatch(data->mHandle, data->mPatch);
219 } break;
220 case RELEASE_AUDIO_PATCH: {
221 ReleaseAudioPatchData *data = (ReleaseAudioPatchData *)command->mData.get();
222 ALOGV("CommandThread() processing release audio patch handle %d", data->mHandle);
223 mManager.onReleaseAudioPatch(data->mHandle);
224 } break;
225 default:
226 ALOGW("CommandThread() unknown command %d", command->mCommand);
227 }
228 mLock.lock();
229 }
230
231 // At this stage we have either an empty command queue or the first command in the queue
232 // has a finite delay. So unless we are exiting it is safe to wait.
233 if (!exitPending()) {
234 ALOGV("CommandThread() going to sleep");
235 mWaitWorkCV.wait(mLock);
236 }
237 }
238 mLock.unlock();
239 return false;
240 }
241
sendCommand(sp<Command> command)242 void AudioFlinger::DeviceEffectManager::CommandThread::sendCommand(sp<Command> command) {
243 Mutex::Autolock _l(mLock);
244 mCommands.push_back(command);
245 mWaitWorkCV.signal();
246 }
247
createAudioPatchCommand(audio_patch_handle_t handle,const PatchPanel::Patch & patch)248 void AudioFlinger::DeviceEffectManager::CommandThread::createAudioPatchCommand(
249 audio_patch_handle_t handle, const PatchPanel::Patch& patch)
250 {
251 sp<Command> command = new Command(CREATE_AUDIO_PATCH, new CreateAudioPatchData(handle, patch));
252 ALOGV("CommandThread() adding create patch handle %d mHalHandle %d.", handle, patch.mHalHandle);
253 sendCommand(command);
254 }
255
releaseAudioPatchCommand(audio_patch_handle_t handle)256 void AudioFlinger::DeviceEffectManager::CommandThread::releaseAudioPatchCommand(
257 audio_patch_handle_t handle)
258 {
259 sp<Command> command = new Command(RELEASE_AUDIO_PATCH, new ReleaseAudioPatchData(handle));
260 ALOGV("CommandThread() adding release patch");
261 sendCommand(command);
262 }
263
exit()264 void AudioFlinger::DeviceEffectManager::CommandThread::exit()
265 {
266 ALOGV("CommandThread::exit");
267 {
268 AutoMutex _l(mLock);
269 requestExit();
270 mWaitWorkCV.signal();
271 }
272 // Note that we can call it from the thread loop if all other references have been released
273 // but it will safely return WOULD_BLOCK in this case
274 requestExitAndWait();
275 }
276
277 } // namespace android
278