Skip to content

Commit d2a6d5c

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

File tree

3 files changed

+429
-1
lines changed

3 files changed

+429
-1
lines changed

Main/libjamesdsp/jni/jamesdsp/Android.bp

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

0 commit comments

Comments
 (0)