blob: 4877956ef7a86587761a09d7200f5a65894182f6 [file] [log] [blame]
Shunkai Yaoc23916b2022-07-13 04:59:37 +00001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "AHAL_EffectFactory"
18#include <android-base/logging.h>
Shunkai Yaoea24c1a2022-09-28 17:39:23 +000019#include <dlfcn.h>
Shunkai Yaoc23916b2022-07-13 04:59:37 +000020
Shunkai Yaoea24c1a2022-09-28 17:39:23 +000021#include "effect-impl/EffectUUID.h"
Shunkai Yaoc23916b2022-07-13 04:59:37 +000022#include "effectFactory-impl/EffectFactory.h"
Shunkai Yaoc23916b2022-07-13 04:59:37 +000023
24using aidl::android::media::audio::common::AudioUuid;
25
26namespace aidl::android::hardware::audio::effect {
27
28Factory::Factory() {
Shunkai Yaoea24c1a2022-09-28 17:39:23 +000029 std::function<void(void*)> dlClose = [](void* handle) -> void {
30 if (handle && dlclose(handle)) {
31 LOG(ERROR) << "dlclose failed " << dlerror();
32 }
33 };
34 // TODO: implement this with audio_effect.xml.
35 auto libHandle =
36 std::unique_ptr<void, decltype(dlClose)>{dlopen("libequalizer.so", RTLD_LAZY), dlClose};
37 if (!libHandle) {
38 LOG(ERROR) << __func__ << ": dlopen failed, err: " << dlerror();
39 return;
40 }
41
42 LOG(DEBUG) << __func__ << " dlopen uuid: " << EqualizerSwImplUUID.toString() << " handle "
43 << libHandle;
44 mEffectLibMap.insert({EqualizerSwImplUUID, std::make_pair(std::move(libHandle), nullptr)});
45
Shunkai Yaoc23916b2022-07-13 04:59:37 +000046 Descriptor::Identity id;
Shunkai Yao121c6dd2022-09-21 23:42:08 +000047 id.type = EqualizerTypeUUID;
48 id.uuid = EqualizerSwImplUUID;
Shunkai Yaoc23916b2022-07-13 04:59:37 +000049 mIdentityList.push_back(id);
Shunkai Yaoc23916b2022-07-13 04:59:37 +000050}
51
Shunkai Yaoea24c1a2022-09-28 17:39:23 +000052Factory::~Factory() {
53 if (auto count = mEffectUuidMap.size()) {
54 LOG(ERROR) << __func__ << " remaining " << count
55 << " effect instances not destroyed indicating resource leak!";
56 for (const auto& it : mEffectUuidMap) {
57 if (auto spEffect = it.first.lock()) {
58 LOG(ERROR) << __func__ << " erase remaining instance UUID " << it.second.toString();
59 destroyEffectImpl(spEffect);
60 }
61 }
62 }
63}
64
65ndk::ScopedAStatus Factory::queryEffects(const std::optional<AudioUuid>& in_type_uuid,
66 const std::optional<AudioUuid>& in_impl_uuid,
Shunkai Yaoc23916b2022-07-13 04:59:37 +000067 std::vector<Descriptor::Identity>* _aidl_return) {
68 std::copy_if(mIdentityList.begin(), mIdentityList.end(), std::back_inserter(*_aidl_return),
69 [&](auto& desc) {
Shunkai Yaoea24c1a2022-09-28 17:39:23 +000070 return (!in_type_uuid.has_value() || in_type_uuid.value() == desc.type) &&
71 (!in_impl_uuid.has_value() || in_impl_uuid.value() == desc.uuid);
Shunkai Yaoc23916b2022-07-13 04:59:37 +000072 });
73 return ndk::ScopedAStatus::ok();
74}
75
Shunkai Yaoea24c1a2022-09-28 17:39:23 +000076#define RETURN_IF_BINDER_EXCEPTION(functor) \
77 { \
78 binder_exception_t exception = functor; \
79 if (EX_NONE != exception) { \
80 LOG(ERROR) << #functor << ": failed with error " << exception; \
81 return ndk::ScopedAStatus::fromExceptionCode(exception); \
82 } \
83 }
84
85ndk::ScopedAStatus Factory::createEffect(const AudioUuid& in_impl_uuid,
86 std::shared_ptr<IEffect>* _aidl_return) {
Shunkai Yao45905172022-08-24 18:14:02 +000087 LOG(DEBUG) << __func__ << ": UUID " << in_impl_uuid.toString();
Shunkai Yao121c6dd2022-09-21 23:42:08 +000088 if (in_impl_uuid == EqualizerSwImplUUID) {
Shunkai Yaoea24c1a2022-09-28 17:39:23 +000089 if (mEffectLibMap.count(in_impl_uuid)) {
90 auto& lib = mEffectLibMap[in_impl_uuid];
91 // didn't do dlsym yet
92 if (nullptr == lib.second) {
93 void* libHandle = lib.first.get();
94 struct effect_interface_s intf = {
95 .createEffectFunc = (EffectCreateFunctor)dlsym(libHandle, "createEffect"),
96 .destroyEffectFunc =
97 (EffectDestroyFunctor)dlsym(libHandle, "destroyEffect")};
98 auto dlInterface = std::make_unique<struct effect_interface_s>(intf);
99 if (!dlInterface->createEffectFunc || !dlInterface->destroyEffectFunc) {
100 LOG(ERROR) << __func__
101 << ": create or destroy symbol not exist in library: " << libHandle
102 << "!";
103 return ndk::ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
104 }
105 lib.second = std::move(dlInterface);
106 }
107
108 auto& libInterface = lib.second;
109 std::shared_ptr<IEffect> effectSp;
110 RETURN_IF_BINDER_EXCEPTION(libInterface->createEffectFunc(&effectSp));
111 if (!effectSp) {
112 LOG(ERROR) << __func__ << ": library created null instance without return error!";
113 return ndk::ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
114 }
115 *_aidl_return = effectSp;
116 mEffectUuidMap[std::weak_ptr<IEffect>(effectSp)] = in_impl_uuid;
117 LOG(DEBUG) << __func__ << ": instance " << effectSp.get() << " created successfully";
118 return ndk::ScopedAStatus::ok();
119 } else {
120 LOG(ERROR) << __func__ << ": library doesn't exist";
121 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
122 }
Shunkai Yao45905172022-08-24 18:14:02 +0000123 } else {
Shunkai Yaoea24c1a2022-09-28 17:39:23 +0000124 LOG(ERROR) << __func__ << ": UUID not supported";
Shunkai Yao45905172022-08-24 18:14:02 +0000125 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
126 }
127 return ndk::ScopedAStatus::ok();
128}
129
Shunkai Yaoea24c1a2022-09-28 17:39:23 +0000130ndk::ScopedAStatus Factory::destroyEffectImpl(const std::shared_ptr<IEffect>& in_handle) {
131 std::weak_ptr<IEffect> wpHandle(in_handle);
132 // find UUID with key (std::weak_ptr<IEffect>)
133 if (auto uuidIt = mEffectUuidMap.find(wpHandle); uuidIt != mEffectUuidMap.end()) {
134 auto& uuid = uuidIt->second;
135 // find implementation library with UUID
136 if (auto libIt = mEffectLibMap.find(uuid); libIt != mEffectLibMap.end()) {
137 if (libIt->second.second->destroyEffectFunc) {
138 RETURN_IF_BINDER_EXCEPTION(libIt->second.second->destroyEffectFunc(in_handle));
139 }
140 } else {
141 LOG(ERROR) << __func__ << ": UUID " << uuid.toString() << " does not exist in libMap!";
142 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
143 }
144 mEffectUuidMap.erase(uuidIt);
Shunkai Yao45905172022-08-24 18:14:02 +0000145 return ndk::ScopedAStatus::ok();
146 } else {
Shunkai Yaoea24c1a2022-09-28 17:39:23 +0000147 LOG(ERROR) << __func__ << ": instance " << in_handle << " does not exist!";
Shunkai Yao45905172022-08-24 18:14:02 +0000148 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
149 }
150}
151
Shunkai Yaoea24c1a2022-09-28 17:39:23 +0000152// go over the map and cleanup all expired weak_ptrs.
153void Factory::cleanupEffectMap() {
154 for (auto it = mEffectUuidMap.begin(); it != mEffectUuidMap.end();) {
155 if (nullptr == it->first.lock()) {
156 it = mEffectUuidMap.erase(it);
157 } else {
158 ++it;
159 }
160 }
161}
162
163ndk::ScopedAStatus Factory::destroyEffect(const std::shared_ptr<IEffect>& in_handle) {
164 LOG(DEBUG) << __func__ << ": instance " << in_handle.get();
165 ndk::ScopedAStatus status = destroyEffectImpl(in_handle);
166 // always do the cleanup
167 cleanupEffectMap();
168 return status;
169}
170
Shunkai Yaoc23916b2022-07-13 04:59:37 +0000171} // namespace aidl::android::hardware::audio::effect