blob: 2754bb62e9d9c7860d4b4620d0d4b98a04a74ffc [file] [log] [blame]
Shunkai Yao6afc8552022-10-26 22:47:20 +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_EffectImpl"
18#include "effect-impl/EffectImpl.h"
19#include "effect-impl/EffectTypes.h"
20#include "include/effect-impl/EffectTypes.h"
21
22namespace aidl::android::hardware::audio::effect {
23
24ndk::ScopedAStatus EffectImpl::open(const Parameter::Common& common,
25 const std::optional<Parameter::Specific>& specific,
26 OpenEffectReturn* ret) {
27 LOG(DEBUG) << __func__;
28 {
29 std::lock_guard lg(mMutex);
30 RETURN_OK_IF(mState != State::INIT);
31 mContext = createContext(common);
32 RETURN_IF(!mContext, EX_ILLEGAL_ARGUMENT, "createContextFailed");
33 setContext(mContext);
34 }
35
36 RETURN_IF_ASTATUS_NOT_OK(setParameterCommon(common), "setCommParamErr");
37 if (specific.has_value()) {
38 RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(specific.value()), "setSpecParamErr");
39 }
40
41 RETURN_IF(createThread(LOG_TAG) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
42 "FailedToCreateWorker");
43
44 {
45 std::lock_guard lg(mMutex);
46 mContext->dupeFmq(ret);
47 mState = State::IDLE;
48 }
49 return ndk::ScopedAStatus::ok();
50}
51
52ndk::ScopedAStatus EffectImpl::close() {
53 std::lock_guard lg(mMutex);
54 RETURN_OK_IF(mState == State::INIT);
55 RETURN_IF(mState == State::PROCESSING, EX_ILLEGAL_STATE, "closeAtProcessing");
56
57 // stop the worker thread, ignore the return code
58 RETURN_IF(destroyThread() != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
59 "FailedToDestroyWorker");
60 RETURN_IF(releaseContext() != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
61 "FailedToCreateWorker");
62 mState = State::INIT;
63 LOG(DEBUG) << __func__;
64 return ndk::ScopedAStatus::ok();
65}
66
67ndk::ScopedAStatus EffectImpl::setParameter(const Parameter& param) {
68 LOG(DEBUG) << __func__ << " with: " << param.toString();
69
70 auto tag = param.getTag();
71 switch (tag) {
72 case Parameter::common:
73 case Parameter::deviceDescription:
74 case Parameter::mode:
75 case Parameter::source:
76 FALLTHROUGH_INTENDED;
77 case Parameter::volumeStereo:
78 return setParameterCommon(param);
79 case Parameter::specific: {
80 return setParameterSpecific(param.get<Parameter::specific>());
81 }
82 default: {
83 LOG(ERROR) << __func__ << " unsupportedParameterTag " << toString(tag);
84 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
85 "ParameterNotSupported");
86 }
87 }
88}
89
90ndk::ScopedAStatus EffectImpl::getParameter(const Parameter::Id& id, Parameter* param) {
91 LOG(DEBUG) << __func__ << id.toString();
92 auto tag = id.getTag();
93 switch (tag) {
94 case Parameter::Id::commonTag: {
95 RETURN_IF_ASTATUS_NOT_OK(getParameterCommon(id.get<Parameter::Id::commonTag>(), param),
96 "CommonParamNotSupported");
97 break;
98 }
99 case Parameter::Id::vendorEffectTag: {
100 LOG(DEBUG) << __func__ << " noop for vendor tag";
101 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
102 "vendortagNotSupported");
103 }
104 default: {
105 Parameter::Specific specific;
106 RETURN_IF_ASTATUS_NOT_OK(getParameterSpecific(id, &specific), "SpecParamNotSupported");
107 param->set<Parameter::specific>(specific);
108 break;
109 }
110 }
111 LOG(DEBUG) << __func__ << param->toString();
112 return ndk::ScopedAStatus::ok();
113}
114
115ndk::ScopedAStatus EffectImpl::setParameterCommon(const Parameter& param) {
116 std::lock_guard lg(mMutex);
117 RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
118 auto tag = param.getTag();
119 switch (tag) {
120 case Parameter::common:
121 RETURN_IF(mContext->setCommon(param.get<Parameter::common>()) != RetCode::SUCCESS,
122 EX_ILLEGAL_ARGUMENT, "setCommFailed");
123 break;
124 case Parameter::deviceDescription:
125 RETURN_IF(mContext->setOutputDevice(param.get<Parameter::deviceDescription>()) !=
126 RetCode::SUCCESS,
127 EX_ILLEGAL_ARGUMENT, "setDeviceFailed");
128 break;
129 case Parameter::mode:
130 RETURN_IF(mContext->setAudioMode(param.get<Parameter::mode>()) != RetCode::SUCCESS,
131 EX_ILLEGAL_ARGUMENT, "setModeFailed");
132 break;
133 case Parameter::source:
134 RETURN_IF(mContext->setAudioSource(param.get<Parameter::source>()) != RetCode::SUCCESS,
135 EX_ILLEGAL_ARGUMENT, "setSourceFailed");
136 break;
137 case Parameter::volumeStereo:
138 RETURN_IF(mContext->setVolumeStereo(param.get<Parameter::volumeStereo>()) !=
139 RetCode::SUCCESS,
140 EX_ILLEGAL_ARGUMENT, "setVolumeStereoFailed");
141 break;
142 default: {
143 LOG(ERROR) << __func__ << " unsupportedParameterTag " << toString(tag);
144 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
145 "commonParamNotSupported");
146 }
147 }
148 return ndk::ScopedAStatus::ok();
149}
150
151ndk::ScopedAStatus EffectImpl::getParameterCommon(const Parameter::Tag& tag, Parameter* param) {
152 std::lock_guard lg(mMutex);
153 RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
154 switch (tag) {
155 case Parameter::common: {
156 param->set<Parameter::common>(mContext->getCommon());
157 break;
158 }
159 case Parameter::deviceDescription: {
160 param->set<Parameter::deviceDescription>(mContext->getOutputDevice());
161 break;
162 }
163 case Parameter::mode: {
164 param->set<Parameter::mode>(mContext->getAudioMode());
165 break;
166 }
167 case Parameter::source: {
168 param->set<Parameter::source>(mContext->getAudioSource());
169 break;
170 }
171 case Parameter::volumeStereo: {
172 param->set<Parameter::volumeStereo>(mContext->getVolumeStereo());
173 break;
174 }
175 default: {
176 LOG(DEBUG) << __func__ << " unsupported tag " << toString(tag);
177 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
178 "tagNotSupported");
179 }
180 }
181 return ndk::ScopedAStatus::ok();
182}
183
184ndk::ScopedAStatus EffectImpl::getState(State* state) {
185 std::lock_guard lg(mMutex);
186 *state = mState;
187 return ndk::ScopedAStatus::ok();
188}
189
190ndk::ScopedAStatus EffectImpl::command(CommandId command) {
191 std::lock_guard lg(mMutex);
192 LOG(DEBUG) << __func__ << ": receive command: " << toString(command) << " at state "
193 << toString(mState);
194 RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "CommandStateError");
195 RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
196
197 switch (command) {
198 case CommandId::START:
199 RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "instanceNotOpen");
200 RETURN_OK_IF(mState == State::PROCESSING);
201 RETURN_IF_ASTATUS_NOT_OK(commandStart(), "commandStartFailed");
202 mState = State::PROCESSING;
203 startThread();
204 return ndk::ScopedAStatus::ok();
205 case CommandId::STOP:
206 RETURN_OK_IF(mState == State::IDLE);
207 mState = State::IDLE;
208 RETURN_IF_ASTATUS_NOT_OK(commandStop(), "commandStopFailed");
209 stopThread();
210 return ndk::ScopedAStatus::ok();
211 case CommandId::RESET:
212 RETURN_OK_IF(mState == State::IDLE);
213 mState = State::IDLE;
214 RETURN_IF_ASTATUS_NOT_OK(commandStop(), "commandStopFailed");
215 stopThread();
216 mContext->resetBuffer();
217 return ndk::ScopedAStatus::ok();
218 default:
219 LOG(ERROR) << __func__ << " instance still processing";
220 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
221 "CommandIdNotSupported");
222 }
223 LOG(DEBUG) << __func__ << " transfer to state: " << toString(mState);
224 return ndk::ScopedAStatus::ok();
225}
226
227void EffectImpl::cleanUp() {
228 command(CommandId::STOP);
229 close();
230}
231
232IEffect::Status EffectImpl::status(binder_status_t status, size_t consumed, size_t produced) {
233 IEffect::Status ret;
234 ret.status = status;
235 ret.fmqConsumed = consumed;
236 ret.fmqProduced = produced;
237 return ret;
238}
239
240// A placeholder processing implementation to copy samples from input to output
241IEffect::Status EffectImpl::effectProcessImpl(float* in, float* out, int processSamples) {
242 // lock before access context/parameters
243 std::lock_guard lg(mMutex);
244 IEffect::Status status = {EX_NULL_POINTER, 0, 0};
245 RETURN_VALUE_IF(!mContext, status, "nullContext");
246 auto frameSize = mContext->getInputFrameSize();
247 RETURN_VALUE_IF(0 == frameSize, status, "frameSizeIs0");
248 LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << processSamples
249 << " frames " << processSamples * sizeof(float) / frameSize;
250 for (int i = 0; i < processSamples; i++) {
251 *out++ = *in++;
252 }
253 LOG(DEBUG) << __func__ << " done processing " << processSamples << " samples";
254 return {STATUS_OK, processSamples, processSamples};
255}
256} // namespace aidl::android::hardware::audio::effect