Skip to content

Commit df9c7e8

Browse files
committed
Implement AIDL JamesDSP effect
1 parent 8060fe2 commit df9c7e8

3 files changed

Lines changed: 430 additions & 1 deletion

File tree

Main/libjamesdsp/jni/jamesdsp/Android.bp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ cc_defaults {
108108
"libhardware_headers",
109109
],
110110
lto: {
111-
// TODO: full was removed in 0713e336d9898aad7c161e92b8d27096142b64b6 (build/soong)
111+
// TODO: full was removed in https://android-review.googlesource.com/c/platform/build/soong/+/2609595
112112
thin: true,
113113
},
114114
}
@@ -135,6 +135,9 @@ cc_defaults {
135135
shared_libs: [
136136
"liblog",
137137
],
138+
cflags: [
139+
"-DBACKEND_NDK",
140+
],
138141
}
139142

140143
cc_library_shared {
@@ -151,3 +154,22 @@ cc_library_shared {
151154
"-fvisibility=hidden",
152155
],
153156
}
157+
158+
cc_library_shared {
159+
name: "libjamesdspaidl",
160+
vendor: true,
161+
relative_install_path: "soundfx",
162+
defaults: [
163+
"aidlaudioeffectservice_defaults",
164+
"jdspEffectDefaults",
165+
],
166+
srcs: [
167+
"jamesdsp_aidl.cpp",
168+
// AOSP
169+
":effectCommonFile",
170+
],
171+
static_libs: [
172+
"libaudio_aidl_conversion_common_ndk",
173+
"libstagefright_foundation",
174+
],
175+
}
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
/*
2+
* Copyright (C) 2022 The Android Open Source Project
3+
* 2025 anonymix007
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+
#include <algorithm>
19+
#include <cstddef>
20+
21+
#define LOG_TAG "JamesDSP_AIDL"
22+
#include <android-base/logging.h>
23+
24+
#include <aidl/android/hardware/audio/effect/DefaultExtension.h>
25+
#include <fmq/AidlMessageQueue.h>
26+
#include <media/AidlConversionNdk.h>
27+
#include <system/audio_effects/effect_uuid.h>
28+
29+
#include "jamesdsp_aidl.h"
30+
31+
using aidl::android::hardware::audio::effect::Descriptor;
32+
using aidl::android::hardware::audio::effect::DefaultExtension;
33+
using aidl::android::hardware::audio::effect::JamesDSPAIDL;
34+
using aidl::android::hardware::audio::effect::getEffectTypeUuidCustom;
35+
using aidl::android::hardware::audio::effect::getEffectImplUuidJDSP;
36+
using aidl::android::hardware::audio::effect::getEffectUuidNull;
37+
using aidl::android::hardware::audio::effect::IEffect;
38+
using aidl::android::hardware::audio::effect::State;
39+
using aidl::android::hardware::audio::effect::VendorExtension;
40+
using aidl::android::media::audio::common::AudioUuid;
41+
42+
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
43+
std::shared_ptr<IEffect>* instanceSpp) {
44+
if (!in_impl_uuid || *in_impl_uuid != getEffectImplUuidJDSP()) {
45+
LOG(ERROR) << __func__ << "uuid not supported";
46+
return EX_ILLEGAL_ARGUMENT;
47+
}
48+
if (instanceSpp) {
49+
*instanceSpp = ndk::SharedRefBase::make<JamesDSPAIDL>();
50+
LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
51+
return EX_NONE;
52+
} else {
53+
LOG(ERROR) << __func__ << " invalid input parameter!";
54+
return EX_ILLEGAL_ARGUMENT;
55+
}
56+
}
57+
58+
extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
59+
if (!in_impl_uuid || *in_impl_uuid != getEffectImplUuidJDSP()) {
60+
LOG(ERROR) << __func__ << "uuid not supported";
61+
return EX_ILLEGAL_ARGUMENT;
62+
}
63+
*_aidl_return = JamesDSPAIDL::kDesc;
64+
return EX_NONE;
65+
}
66+
67+
namespace aidl::android::hardware::audio::effect {
68+
69+
#if __aarch64__ == 1
70+
const std::string JamesDSPAIDL::kEffectName = "James Audio DSP arm64";
71+
#elif __ARM_ARCH_7A__ == 1
72+
const std::string JamesDSPAIDL::kEffectName = "James Audio DSP arm32";
73+
#elif __i386__ == 1
74+
const std::string JamesDSPAIDL::kEffectName = "James Audio DSP x86";
75+
#elif __x86_64__ == 1
76+
const std::string JamesDSPAIDL::kEffectName = "James Audio DSP x64";
77+
#endif
78+
79+
const Descriptor JamesDSPAIDL::kDesc = {.common = {.id = {.type = getEffectTypeUuidCustom(),
80+
.uuid = getEffectImplUuidJDSP()},
81+
.flags = {.type = Flags::Type::INSERT,
82+
.insert = Flags::Insert::LAST,
83+
.volume = Flags::Volume::CTRL},
84+
.name = JamesDSPAIDL::kEffectName,
85+
.implementor = "James Fung"}};
86+
87+
ndk::ScopedAStatus JamesDSPAIDL::getDescriptor(Descriptor* _aidl_return) {
88+
LOG(DEBUG) << __func__ << kDesc.toString();
89+
*_aidl_return = kDesc;
90+
return ndk::ScopedAStatus::ok();
91+
}
92+
93+
ndk::ScopedAStatus JamesDSPAIDL::setParameterSpecific(const Parameter::Specific& specific) {
94+
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
95+
RETURN_IF(Parameter::Specific::vendorEffect != specific.getTag(), EX_ILLEGAL_ARGUMENT, "EffectNotSupported");
96+
auto& vendorEffect = specific.get<Parameter::Specific::vendorEffect>();
97+
std::optional<DefaultExtension> defaultExt;
98+
RETURN_IF(STATUS_OK != vendorEffect.extension.getParcelable(&defaultExt), EX_ILLEGAL_ARGUMENT, "getParcelableFailed");
99+
RETURN_IF(!defaultExt.has_value(), EX_ILLEGAL_ARGUMENT, "parcelableNull");
100+
101+
#ifdef AIDL_DEBUG
102+
LOG(DEBUG) << __func__ << ": defaultExt: " << defaultExt->toString();
103+
#endif
104+
105+
int32_t ret = 0;
106+
uint32_t ret_size = sizeof(ret);
107+
RETURN_IF(mContext->handleCommand(EFFECT_CMD_SET_PARAM, defaultExt->bytes.size(), defaultExt->bytes.data(), &ret_size, &ret) != 0, EX_ILLEGAL_ARGUMENT, "handleCommandFailed");
108+
RETURN_IF(ret != 0, EX_ILLEGAL_ARGUMENT, "handleCommandInternalFailed");
109+
return ndk::ScopedAStatus::ok();
110+
}
111+
112+
ndk::ScopedAStatus JamesDSPAIDL::getParameterSpecific(const Parameter::Id& id,
113+
Parameter::Specific* specific) {
114+
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
115+
RETURN_IF(Parameter::Id::vendorEffectTag != id.getTag(), EX_ILLEGAL_ARGUMENT, "wrongIdTag");
116+
auto extensionId = id.get<Parameter::Id::vendorEffectTag>();
117+
std::optional<DefaultExtension> defaultIdExt;
118+
RETURN_IF(STATUS_OK != extensionId.extension.getParcelable(&defaultIdExt), EX_ILLEGAL_ARGUMENT, "getIdParcelableFailed");
119+
RETURN_IF(!defaultIdExt.has_value(), EX_ILLEGAL_ARGUMENT, "parcelableIdNull");
120+
121+
#ifdef AIDL_DEBUG
122+
LOG(DEBUG) << __func__ << ": defaultIdExt: " << defaultIdExt->toString();
123+
#endif
124+
125+
VendorExtension extension;
126+
DefaultExtension defaultExt;
127+
defaultExt.bytes.resize(sizeof(effect_param_t) + 2 * sizeof(int32_t));
128+
uint32_t data_size = defaultExt.bytes.size();
129+
RETURN_IF(mContext->handleCommand(EFFECT_CMD_GET_PARAM, defaultIdExt->bytes.size(), defaultIdExt->bytes.data(), &data_size, defaultExt.bytes.data()) != 0, EX_ILLEGAL_ARGUMENT, "handleCommandFailed");
130+
assert(data_size <= defaultExt.bytes.size());
131+
defaultExt.bytes.resize(data_size);
132+
133+
#ifdef AIDL_DEBUG
134+
LOG(DEBUG) << __func__ << ": defaultExt: " << defaultExt.toString();
135+
#endif
136+
137+
RETURN_IF(STATUS_OK != extension.extension.setParcelable(defaultExt), EX_ILLEGAL_ARGUMENT, "setParcelableFailed");
138+
specific->set<Parameter::Specific::vendorEffect>(extension);
139+
return ndk::ScopedAStatus::ok();
140+
}
141+
142+
static inline std::string buffer_config_to_string(const buffer_config_t &conf) {
143+
std::ostringstream stream_out;
144+
stream_out << "rate: " << conf.samplingRate << ", channels: " << conf.channels << ", format: " << (int) conf.format;
145+
return stream_out.str();
146+
}
147+
148+
std::shared_ptr<EffectContext> JamesDSPAIDL::createContext(const Parameter::Common& common) {
149+
if (mContext) {
150+
LOG(DEBUG) << __func__ << " context already exists";
151+
} else {
152+
mContext = std::make_shared<JamesDSPAIDLContext>(1 /* statusFmqDepth */, common);
153+
int32_t ret = 0;
154+
uint32_t ret_size = sizeof(ret);
155+
int32_t status = mContext->handleCommand(EFFECT_CMD_INIT, 0, NULL, &ret_size, &ret);
156+
if (status < 0) {
157+
LOG(ERROR) << __func__ << ": JamesDSPAIDLContext::handleCommand INIT failed: " << status;
158+
mContext = nullptr;
159+
return mContext;
160+
}
161+
if (ret < 0) {
162+
LOG(ERROR) << __func__ << ": JamesDSPAIDLContext::handleCommand INIT failed (internal): " << ret;
163+
mContext = nullptr;
164+
return mContext;
165+
}
166+
ret = 0;
167+
ret_size = sizeof(ret);
168+
effect_config_t conf;
169+
170+
if (!aidl2legacy_ParameterCommon_effect_config_t(common, conf)) {
171+
LOG(ERROR) << __func__ << ": JamesDSPAIDL::createContext: aidl2legacy_ParameterCommon_effect_config_t failed";
172+
mContext = nullptr;
173+
return mContext;
174+
}
175+
176+
LOG(INFO) << __func__ << ": AIDL input config: " << common.input.toString();
177+
LOG(INFO) << __func__ << ": AIDL output config: " << common.output.toString();
178+
LOG(INFO) << __func__ << ": Legacy input config: " << buffer_config_to_string(conf.inputCfg);
179+
LOG(INFO) << __func__ << ": Legacy output config: " << buffer_config_to_string(conf.outputCfg);
180+
181+
status = mContext->handleCommand(EFFECT_CMD_SET_CONFIG, sizeof(conf), &conf, &ret_size, &ret);
182+
if (status < 0) {
183+
LOG(ERROR) << __func__ << ": JamesDSPAIDLContext::handleCommand SET CONFIG failed: " << status;
184+
mContext = nullptr;
185+
return mContext;
186+
}
187+
if (ret < 0) {
188+
LOG(ERROR) << __func__ << ": JamesDSPAIDLContext::handleCommand SET CONFIG failed (internal): " << ret;
189+
mContext = nullptr;
190+
return mContext;
191+
}
192+
}
193+
194+
return mContext;
195+
}
196+
197+
ndk::ScopedAStatus JamesDSPAIDL::commandImpl(CommandId command) {
198+
RETURN_IF(!mImplContext, EX_NULL_POINTER, "nullContext");
199+
int32_t ret = 0;
200+
uint32_t ret_size = sizeof(ret);
201+
switch (command) {
202+
case CommandId::START:
203+
RETURN_IF(mContext->handleCommand(EFFECT_CMD_ENABLE, 0, NULL, &ret_size, &ret) != 0, EX_ILLEGAL_ARGUMENT, "handleCommandFailed");
204+
RETURN_IF(ret != 0, EX_ILLEGAL_ARGUMENT, "handleCommandInternalFailed");
205+
break;
206+
case CommandId::STOP:
207+
RETURN_IF(mContext->handleCommand(EFFECT_CMD_DISABLE, 0, NULL, &ret_size, &ret) != 0, EX_ILLEGAL_ARGUMENT, "handleCommandFailed");
208+
RETURN_IF(ret != 0, EX_ILLEGAL_ARGUMENT, "handleCommandInternalFailed");
209+
break;
210+
case CommandId::RESET:
211+
mImplContext->resetBuffer();
212+
break;
213+
default:
214+
break;
215+
}
216+
return ndk::ScopedAStatus::ok();
217+
}
218+
219+
RetCode JamesDSPAIDL::releaseContext() {
220+
if (mContext) {
221+
int32_t ret = 0;
222+
uint32_t ret_size = sizeof(ret);
223+
int32_t status = mContext->handleCommand(EFFECT_CMD_RESET, 0, NULL, &ret_size, &ret);
224+
if (status < 0) {
225+
LOG(ERROR) << __func__ << ": JamesDSPAIDLContext::handleCommand RESET failed: " << status;
226+
return RetCode::ERROR_ILLEGAL_PARAMETER;
227+
}
228+
if (ret < 0) {
229+
LOG(ERROR) << __func__ << ": JamesDSPAIDLContext::handleCommand RESET failed (internal): " << ret;
230+
return RetCode::ERROR_ILLEGAL_PARAMETER;
231+
}
232+
mContext.reset();
233+
}
234+
return RetCode::SUCCESS;
235+
}
236+
237+
// Processing method running in EffectWorker thread.
238+
IEffect::Status JamesDSPAIDL::effectProcessImpl(float* in_, float* out_, int samples) {
239+
size_t frames = static_cast<size_t>(samples) / 2;
240+
audio_buffer_t in{frames, {in_}}, out{frames, {out_}};
241+
242+
#ifdef AIDL_DEBUG
243+
LOG(DEBUG) << __func__ << ": in " << in_ << ", out " << out_ << ", samples " << samples;
244+
#endif
245+
int32_t ret = mContext->process(&in, &out);
246+
#ifdef AIDL_DEBUG
247+
LOG(DEBUG) << __func__ << ": mContext->process: " << ret;
248+
#endif
249+
250+
switch(ret) {
251+
case 0:
252+
return {STATUS_OK, samples, samples};
253+
case -ENODATA:
254+
return {STATUS_NOT_ENOUGH_DATA, 0, 0};
255+
default:
256+
return {STATUS_INVALID_OPERATION, 0, 0};
257+
}
258+
}
259+
260+
} // namespace aidl::android::hardware::audio::effect

0 commit comments

Comments
 (0)