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