Skip to content

Commit abc52ad

Browse files
committed
Implement AIDL JamesDSP effect
1 parent 32d4978 commit abc52ad

File tree

3 files changed

+431
-0
lines changed

3 files changed

+431
-0
lines changed

Main/libjamesdsp/jni/jamesdsp/Android.bp

+22
Original file line numberDiff line numberDiff line change
@@ -151,3 +151,25 @@ 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+
shared_libs: [
169+
"libbinder",
170+
],
171+
whole_static_libs: [
172+
"libaudio_aidl_conversion_common_ndk",
173+
"libstagefright_foundation",
174+
],
175+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
/*
2+
* Copyright (C) 2022 The Android Open Source Project
3+
* 2024 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+
#include <fmq/AidlMessageQueue.h>
24+
#include <system/audio_effects/effect_uuid.h>
25+
#include <aidl/android/hardware/audio/effect/DefaultExtension.h>
26+
#include <media/AidlConversionUtil.h>
27+
template <typename T>
28+
using ConversionResult = ::android::error::Result<T>;
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+
LOG(DEBUG) << __func__ << ": " << specific.toString();
97+
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
98+
RETURN_IF(Parameter::Specific::vendorEffect != specific.getTag(), EX_ILLEGAL_ARGUMENT, "EffectNotSupported");
99+
auto& vendorEffect = specific.get<Parameter::Specific::vendorEffect>();
100+
std::optional<DefaultExtension> defaultExt;
101+
RETURN_IF(STATUS_OK != vendorEffect.extension.getParcelable(&defaultExt), EX_ILLEGAL_ARGUMENT, "getParcelableFailed");
102+
RETURN_IF(!defaultExt.has_value(), EX_ILLEGAL_ARGUMENT, "parcelableNull");
103+
104+
#ifdef DEBUG
105+
LOG(DEBUG) << __func__ << ": defaultExt: " << defaultExt->toString();
106+
#endif
107+
108+
int32_t ret = 0;
109+
uint32_t ret_size = sizeof(ret);
110+
RETURN_IF(mContext->handleCommand(EFFECT_CMD_SET_PARAM, defaultExt->bytes.size(), defaultExt->bytes.data(), &ret_size, &ret) != 0, EX_ILLEGAL_ARGUMENT, "handleCommandFailed");
111+
RETURN_IF(ret != 0, EX_ILLEGAL_ARGUMENT, "handleCommandInternalFailed");
112+
return ndk::ScopedAStatus::ok();
113+
}
114+
115+
ndk::ScopedAStatus JamesDSPAIDL::getParameterSpecific(const Parameter::Id& id,
116+
Parameter::Specific* specific) {
117+
LOG(DEBUG) << __func__ << ": " << specific->toString();
118+
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
119+
RETURN_IF(Parameter::Id::vendorEffectTag != id.getTag(), EX_ILLEGAL_ARGUMENT, "wrongIdTag");
120+
auto extensionId = id.get<Parameter::Id::vendorEffectTag>();
121+
std::optional<DefaultExtension> defaultIdExt;
122+
RETURN_IF(STATUS_OK != extensionId.extension.getParcelable(&defaultIdExt), EX_ILLEGAL_ARGUMENT, "getIdParcelableFailed");
123+
RETURN_IF(!defaultIdExt.has_value(), EX_ILLEGAL_ARGUMENT, "parcelableIdNull");
124+
125+
#ifdef DEBUG
126+
LOG(DEBUG) << __func__ << ": defaultIdExt: " << defaultIdExt->toString();
127+
#endif
128+
129+
VendorExtension extension;
130+
DefaultExtension defaultExt;
131+
defaultExt.bytes.resize(sizeof(effect_param_t) + 2 * sizeof(int32_t));
132+
uint32_t data_size = defaultExt.bytes.size();
133+
RETURN_IF(mContext->handleCommand(EFFECT_CMD_GET_PARAM, defaultIdExt->bytes.size(), defaultIdExt->bytes.data(), &data_size, defaultExt.bytes.data()) != 0, EX_ILLEGAL_ARGUMENT, "handleCommandFailed");
134+
assert(data_size <= defaultExt.bytes.size());
135+
defaultExt.bytes.resize(data_size);
136+
137+
#ifdef DEBUG
138+
LOG(DEBUG) << __func__ << ": defaultExt: " << defaultExt->toString();
139+
#endif
140+
141+
RETURN_IF(STATUS_OK != extension.extension.setParcelable(defaultExt), EX_ILLEGAL_ARGUMENT, "setParcelableFailed");
142+
specific->set<Parameter::Specific::vendorEffect>(extension);
143+
return ndk::ScopedAStatus::ok();
144+
}
145+
146+
static inline std::string buffer_config_to_string(const buffer_config_t &conf) {
147+
std::ostringstream stream_out;
148+
stream_out << "rate: " << conf.samplingRate << ", channels: " << conf.channels << ", format: " << (int) conf.format;
149+
return stream_out.str();
150+
}
151+
152+
std::shared_ptr<EffectContext> JamesDSPAIDL::createContext(const Parameter::Common& common) {
153+
if (mContext) {
154+
LOG(DEBUG) << __func__ << " context already exist";
155+
} else {
156+
mContext = std::make_shared<JamesDSPAIDLContext>(1 /* statusFmqDepth */, common);
157+
int32_t ret = 0;
158+
uint32_t ret_size = sizeof(ret);
159+
int32_t status = mContext->handleCommand(EFFECT_CMD_INIT, 0, NULL, &ret_size, &ret);
160+
if (status < 0) {
161+
LOG(ERROR) << __func__ << ": JamesDSPAIDLContext::handleCommand INIT failed: " << status;
162+
mContext = nullptr;
163+
return mContext;
164+
}
165+
if (ret < 0) {
166+
LOG(ERROR) << __func__ << ": JamesDSPAIDLContext::handleCommand INIT failed (internal): " << ret;
167+
mContext = nullptr;
168+
return mContext;
169+
}
170+
ret = 0;
171+
ret_size = sizeof(ret);
172+
effect_config_t conf;
173+
174+
if (!aidl2legacy_ParameterCommon_effect_config_t(common, conf)) {
175+
LOG(ERROR) << __func__ << ": JamesDSPAIDL::createContext: aidl2legacy_ParameterCommon_effect_config_t failed";
176+
mContext = nullptr;
177+
return mContext;
178+
}
179+
180+
LOG(WARNING) << __func__ << ": AIDL input config: " << common.input.toString();
181+
LOG(WARNING) << __func__ << ": AIDL output config: " << common.output.toString();
182+
183+
LOG(WARNING) << __func__ << ": Legacy input config: " << buffer_config_to_string(conf.inputCfg);
184+
LOG(WARNING) << __func__ << ": Legacy output config: " << buffer_config_to_string(conf.outputCfg);
185+
186+
status = mContext->handleCommand(EFFECT_CMD_SET_CONFIG, sizeof(conf), &conf, &ret_size, &ret);
187+
if (status < 0) {
188+
LOG(ERROR) << __func__ << ": JamesDSPAIDLContext::handleCommand SET CONFIG failed: " << status;
189+
mContext = nullptr;
190+
return mContext;
191+
}
192+
if (ret < 0) {
193+
LOG(ERROR) << __func__ << ": JamesDSPAIDLContext::handleCommand SET CONFIG failed (internal): " << ret;
194+
mContext = nullptr;
195+
return mContext;
196+
}
197+
}
198+
199+
return mContext;
200+
}
201+
202+
ndk::ScopedAStatus JamesDSPAIDL::commandImpl(CommandId command) {
203+
RETURN_IF(!mImplContext, EX_NULL_POINTER, "nullContext");
204+
int32_t ret = 0;
205+
uint32_t ret_size = sizeof(ret);
206+
switch (command) {
207+
case CommandId::START:
208+
RETURN_IF(mContext->handleCommand(EFFECT_CMD_ENABLE, 0, NULL, &ret_size, &ret) != 0, EX_ILLEGAL_ARGUMENT, "handleCommandFailed");
209+
RETURN_IF(ret != 0, EX_ILLEGAL_ARGUMENT, "handleCommandInternalFailed");
210+
break;
211+
case CommandId::STOP:
212+
RETURN_IF(mContext->handleCommand(EFFECT_CMD_DISABLE, 0, NULL, &ret_size, &ret) != 0, EX_ILLEGAL_ARGUMENT, "handleCommandFailed");
213+
RETURN_IF(ret != 0, EX_ILLEGAL_ARGUMENT, "handleCommandInternalFailed");
214+
break;
215+
case CommandId::RESET:
216+
mImplContext->resetBuffer();
217+
break;
218+
default:
219+
break;
220+
}
221+
return ndk::ScopedAStatus::ok();
222+
}
223+
224+
RetCode JamesDSPAIDL::releaseContext() {
225+
if (mContext) {
226+
int32_t ret = 0;
227+
uint32_t ret_size = sizeof(ret);
228+
int32_t status = mContext->handleCommand(EFFECT_CMD_RESET, 0, NULL, &ret_size, &ret);
229+
if (status < 0) {
230+
LOG(ERROR) << __func__ << ": JamesDSPAIDLContext::handleCommand RESET failed: " << status;
231+
return RetCode::ERROR_ILLEGAL_PARAMETER;
232+
}
233+
if (ret < 0) {
234+
LOG(ERROR) << __func__ << ": JamesDSPAIDLContext::handleCommand RESET failed (internal): " << ret;
235+
return RetCode::ERROR_ILLEGAL_PARAMETER;
236+
}
237+
mContext.reset();
238+
}
239+
return RetCode::SUCCESS;
240+
}
241+
242+
// Processing method running in EffectWorker thread.
243+
IEffect::Status JamesDSPAIDL::effectProcessImpl(float* in_, float* out_, int samples) {
244+
audio_buffer_t in{static_cast<size_t>(samples), {in_}}, out{static_cast<size_t>(samples), {out_}};
245+
#ifdef DEBUG
246+
LOG(DEBUG) << __func__ << ": in " << in_ << ", out " << out_ << ", samples " << samples;
247+
#endif
248+
int32_t ret = mContext->process(&in, &out);
249+
#ifdef DEBUG
250+
LOG(DEBUG) << __func__ << ": mContext->process: " << ret;
251+
#endif
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)