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