• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "EffectConfiguration.h"
27 #include <media/audiohal/EffectsFactoryHalInterface.h>
28 
29 // ----------------------------------------------------------------------------
30 
31 
32 namespace android {
33 
34 using detail::AudioHalVersionInfo;
35 using media::IEffectClient;
36 
onCreateAudioPatch(audio_patch_handle_t handle,const PatchPanel::Patch & patch)37 void AudioFlinger::DeviceEffectManager::onCreateAudioPatch(audio_patch_handle_t handle,
38         const PatchPanel::Patch& patch) {
39     ALOGV("%s handle %d mHalHandle %d device sink %08x",
40             __func__, handle, patch.mHalHandle,
41             patch.mAudioPatch.num_sinks > 0 ? patch.mAudioPatch.sinks[0].ext.device.type : 0);
42     Mutex::Autolock _l(mLock);
43     for (auto& effect : mDeviceEffects) {
44         status_t status = effect.second->onCreatePatch(handle, patch);
45         ALOGV("%s Effect onCreatePatch status %d", __func__, status);
46         ALOGW_IF(status == BAD_VALUE, "%s onCreatePatch error %d", __func__, status);
47     }
48 }
49 
onReleaseAudioPatch(audio_patch_handle_t handle)50 void AudioFlinger::DeviceEffectManager::onReleaseAudioPatch(audio_patch_handle_t handle) {
51     ALOGV("%s", __func__);
52     Mutex::Autolock _l(mLock);
53     for (auto& effect : mDeviceEffects) {
54         effect.second->onReleasePatch(handle);
55     }
56 }
57 
58 // 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)59 sp<AudioFlinger::EffectHandle> AudioFlinger::DeviceEffectManager::createEffect_l(
60         effect_descriptor_t *descriptor,
61         const AudioDeviceTypeAddr& device,
62         const sp<AudioFlinger::Client>& client,
63         const sp<IEffectClient>& effectClient,
64         const std::map<audio_patch_handle_t, PatchPanel::Patch>& patches,
65         int *enabled,
66         status_t *status,
67         bool probe,
68         bool notifyFramesProcessed) {
69     sp<DeviceEffectProxy> effect;
70     sp<EffectHandle> handle;
71     status_t lStatus;
72 
73     lStatus = checkEffectCompatibility(descriptor);
74     if (probe || lStatus != NO_ERROR) {
75        *status = lStatus;
76        return handle;
77     }
78 
79     {
80         Mutex::Autolock _l(mLock);
81         auto iter = mDeviceEffects.find(device);
82         if (iter != mDeviceEffects.end()) {
83             effect = iter->second;
84         } else {
85             effect = new DeviceEffectProxy(device, mMyCallback,
86                     descriptor, mAudioFlinger.nextUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT),
87                     notifyFramesProcessed);
88         }
89         // create effect handle and connect it to effect module
90         handle = new EffectHandle(effect, client, effectClient, 0 /*priority*/,
91                                   notifyFramesProcessed);
92         lStatus = handle->initCheck();
93         if (lStatus == NO_ERROR) {
94             lStatus = effect->addHandle(handle.get());
95             if (lStatus == NO_ERROR) {
96                 lStatus = effect->init(patches);
97                 if (lStatus == NAME_NOT_FOUND) {
98                     lStatus = NO_ERROR;
99                 }
100                 if (lStatus == NO_ERROR || lStatus == ALREADY_EXISTS) {
101                     mDeviceEffects.emplace(device, effect);
102                 }
103             }
104         }
105     }
106     if (enabled != nullptr) {
107         *enabled = (int)effect->isEnabled();
108     }
109     *status = lStatus;
110     return handle;
111 }
112 
checkEffectCompatibility(const effect_descriptor_t * desc)113 status_t AudioFlinger::DeviceEffectManager::checkEffectCompatibility(
114         const effect_descriptor_t *desc) {
115     const sp<EffectsFactoryHalInterface> effectsFactory =
116             audioflinger::EffectConfiguration::getEffectsFactoryHal();
117     if (effectsFactory == nullptr) {
118         return BAD_VALUE;
119     }
120 
121     static const AudioHalVersionInfo sMinDeviceEffectHalVersion =
122             AudioHalVersionInfo(AudioHalVersionInfo::Type::HIDL, 6, 0);
123     static const AudioHalVersionInfo halVersion =
124             audioflinger::EffectConfiguration::getAudioHalVersionInfo();
125 
126     // We can trust AIDL generated AudioHalVersionInfo comparison operator (based on std::tie) as
127     // long as the type, major and minor sequence doesn't change in the definition.
128     if (((desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_PRE_PROC
129             && (desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_POST_PROC)
130             || halVersion < sMinDeviceEffectHalVersion) {
131         ALOGW("%s() non pre/post processing device effect %s or incompatible API version %s",
132                 __func__, desc->name, halVersion.toString().c_str());
133         return BAD_VALUE;
134     }
135 
136     return NO_ERROR;
137 }
138 
createEffectHal(const effect_uuid_t * pEffectUuid,int32_t sessionId,int32_t deviceId,sp<EffectHalInterface> * effect)139 status_t AudioFlinger::DeviceEffectManager::createEffectHal(
140         const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t deviceId,
141         sp<EffectHalInterface> *effect) {
142     status_t status = NO_INIT;
143     const sp<EffectsFactoryHalInterface> effectsFactory =
144             audioflinger::EffectConfiguration::getEffectsFactoryHal();
145     if (effectsFactory != 0) {
146         status = effectsFactory->createEffect(
147                 pEffectUuid, sessionId, AUDIO_IO_HANDLE_NONE, deviceId, effect);
148     }
149     return status;
150 }
151 
dump(int fd)152 void AudioFlinger::DeviceEffectManager::dump(int fd)
153 NO_THREAD_SAFETY_ANALYSIS  // conditional try lock
154 {
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 } // namespace android
207