1 /*
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 #include <algorithm>
18 #include <cstddef>
19 #include <optional>
20
21 #define LOG_TAG "AHAL_VirtualizerSw"
22 #include <Utils.h>
23 #include <android-base/logging.h>
24 #include <fmq/AidlMessageQueue.h>
25 #include <system/audio_effects/effect_uuid.h>
26
27 #include "VirtualizerSw.h"
28
29 using aidl::android::hardware::audio::effect::Descriptor;
30 using aidl::android::hardware::audio::effect::getEffectImplUuidVirtualizerSw;
31 using aidl::android::hardware::audio::effect::getEffectTypeUuidVirtualizer;
32 using aidl::android::hardware::audio::effect::IEffect;
33 using aidl::android::hardware::audio::effect::State;
34 using aidl::android::hardware::audio::effect::VirtualizerSw;
35 using aidl::android::media::audio::common::AudioChannelLayout;
36 using aidl::android::media::audio::common::AudioDeviceDescription;
37 using aidl::android::media::audio::common::AudioDeviceType;
38 using aidl::android::media::audio::common::AudioUuid;
39
createEffect(const AudioUuid * in_impl_uuid,std::shared_ptr<IEffect> * instanceSpp)40 extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
41 std::shared_ptr<IEffect>* instanceSpp) {
42 if (!in_impl_uuid || *in_impl_uuid != getEffectImplUuidVirtualizerSw()) {
43 LOG(ERROR) << __func__ << "uuid not supported";
44 return EX_ILLEGAL_ARGUMENT;
45 }
46 if (instanceSpp) {
47 *instanceSpp = ndk::SharedRefBase::make<VirtualizerSw>();
48 LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
49 return EX_NONE;
50 } else {
51 LOG(ERROR) << __func__ << " invalid input parameter!";
52 return EX_ILLEGAL_ARGUMENT;
53 }
54 }
55
queryEffect(const AudioUuid * in_impl_uuid,Descriptor * _aidl_return)56 extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
57 if (!in_impl_uuid || *in_impl_uuid != getEffectImplUuidVirtualizerSw()) {
58 LOG(ERROR) << __func__ << "uuid not supported";
59 return EX_ILLEGAL_ARGUMENT;
60 }
61 *_aidl_return = VirtualizerSw::kDescriptor;
62 return EX_NONE;
63 }
64
65 namespace aidl::android::hardware::audio::effect {
66
67 const std::string VirtualizerSw::kEffectName = "VirtualizerSw";
68
69 const std::vector<Range::VirtualizerRange> VirtualizerSw::kRanges = {
70 MAKE_RANGE(Virtualizer, strengthPm, 0, 1000),
71 /* speakerAngle is get-only, set min > max */
72 MAKE_RANGE(Virtualizer, speakerAngles, {Virtualizer::ChannelAngle({.channel = 1})},
73 {Virtualizer::ChannelAngle({.channel = 0})})};
74
75 const Capability VirtualizerSw::kCapability = {
76 .range = Range::make<Range::virtualizer>(VirtualizerSw::kRanges)};
77
78 const Descriptor VirtualizerSw::kDescriptor = {
79 .common = {.id = {.type = getEffectTypeUuidVirtualizer(),
80 .uuid = getEffectImplUuidVirtualizerSw()},
81 .flags = {.type = Flags::Type::INSERT,
82 .insert = Flags::Insert::FIRST,
83 .volume = Flags::Volume::CTRL},
84 .name = VirtualizerSw::kEffectName,
85 .implementor = "The Android Open Source Project"},
86 .capability = VirtualizerSw::kCapability};
87
getDescriptor(Descriptor * _aidl_return)88 ndk::ScopedAStatus VirtualizerSw::getDescriptor(Descriptor* _aidl_return) {
89 LOG(DEBUG) << __func__ << kDescriptor.toString();
90 *_aidl_return = kDescriptor;
91 return ndk::ScopedAStatus::ok();
92 }
93
setParameterSpecific(const Parameter::Specific & specific)94 ndk::ScopedAStatus VirtualizerSw::setParameterSpecific(const Parameter::Specific& specific) {
95 RETURN_IF(Parameter::Specific::virtualizer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
96 "EffectNotSupported");
97
98 auto& vrParam = specific.get<Parameter::Specific::virtualizer>();
99 RETURN_IF(!inRange(vrParam, kRanges), EX_ILLEGAL_ARGUMENT, "outOfRange");
100 auto tag = vrParam.getTag();
101
102 switch (tag) {
103 case Virtualizer::strengthPm: {
104 RETURN_IF(mContext->setVrStrength(vrParam.get<Virtualizer::strengthPm>()) !=
105 RetCode::SUCCESS,
106 EX_ILLEGAL_ARGUMENT, "setStrengthPmFailed");
107 return ndk::ScopedAStatus::ok();
108 }
109 case Virtualizer::device: {
110 RETURN_IF(mContext->setForcedDevice(vrParam.get<Virtualizer::device>()) !=
111 RetCode::SUCCESS,
112 EX_ILLEGAL_ARGUMENT, "setDeviceFailed");
113 return ndk::ScopedAStatus::ok();
114 }
115 case Virtualizer::speakerAngles:
116 FALLTHROUGH_INTENDED;
117 case Virtualizer::vendor: {
118 LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
119 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
120 "VirtualizerTagNotSupported");
121 }
122 }
123 }
124
getParameterSpecific(const Parameter::Id & id,Parameter::Specific * specific)125 ndk::ScopedAStatus VirtualizerSw::getParameterSpecific(const Parameter::Id& id,
126 Parameter::Specific* specific) {
127 auto tag = id.getTag();
128 RETURN_IF(Parameter::Id::virtualizerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
129 auto vrId = id.get<Parameter::Id::virtualizerTag>();
130 auto vrIdTag = vrId.getTag();
131 switch (vrIdTag) {
132 case Virtualizer::Id::commonTag:
133 return getParameterVirtualizer(vrId.get<Virtualizer::Id::commonTag>(), specific);
134 case Virtualizer::Id::speakerAnglesPayload:
135 return getSpeakerAngles(vrId.get<Virtualizer::Id::speakerAnglesPayload>(), specific);
136 case Virtualizer::Id::vendorExtensionTag: {
137 LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
138 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
139 "VirtualizerTagNotSupported");
140 }
141 }
142 }
143
getParameterVirtualizer(const Virtualizer::Tag & tag,Parameter::Specific * specific)144 ndk::ScopedAStatus VirtualizerSw::getParameterVirtualizer(const Virtualizer::Tag& tag,
145 Parameter::Specific* specific) {
146 RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
147
148 Virtualizer vrParam;
149 switch (tag) {
150 case Virtualizer::strengthPm: {
151 vrParam.set<Virtualizer::strengthPm>(mContext->getVrStrength());
152 break;
153 }
154 case Virtualizer::device: {
155 vrParam.set<Virtualizer::device>(mContext->getForcedDevice());
156 break;
157 }
158 case Virtualizer::speakerAngles:
159 FALLTHROUGH_INTENDED;
160 case Virtualizer::vendor: {
161 LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
162 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
163 "VirtualizerTagNotSupported");
164 }
165 }
166
167 specific->set<Parameter::Specific::virtualizer>(vrParam);
168 return ndk::ScopedAStatus::ok();
169 }
170
getSpeakerAngles(const Virtualizer::SpeakerAnglesPayload payload,Parameter::Specific * specific)171 ndk::ScopedAStatus VirtualizerSw::getSpeakerAngles(const Virtualizer::SpeakerAnglesPayload payload,
172 Parameter::Specific* specific) {
173 std::vector<Virtualizer::ChannelAngle> angles;
174 const auto chNum = ::aidl::android::hardware::audio::common::getChannelCount(payload.layout);
175 if (chNum == 1) {
176 angles = {{.channel = (int32_t)AudioChannelLayout::CHANNEL_FRONT_LEFT,
177 .azimuthDegree = 0,
178 .elevationDegree = 0}};
179 } else if (chNum == 2) {
180 angles = {{.channel = (int32_t)AudioChannelLayout::CHANNEL_FRONT_LEFT,
181 .azimuthDegree = -90,
182 .elevationDegree = 0},
183 {.channel = (int32_t)AudioChannelLayout::CHANNEL_FRONT_RIGHT,
184 .azimuthDegree = 90,
185 .elevationDegree = 0}};
186 } else {
187 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
188 "supportUpTo2Ch");
189 }
190
191 Virtualizer param = Virtualizer::make<Virtualizer::speakerAngles>(angles);
192 specific->set<Parameter::Specific::virtualizer>(param);
193 return ndk::ScopedAStatus::ok();
194 }
195
createContext(const Parameter::Common & common)196 std::shared_ptr<EffectContext> VirtualizerSw::createContext(const Parameter::Common& common) {
197 if (mContext) {
198 LOG(DEBUG) << __func__ << " context already exist";
199 } else {
200 mContext = std::make_shared<VirtualizerSwContext>(1 /* statusFmqDepth */, common);
201 }
202
203 return mContext;
204 }
205
releaseContext()206 RetCode VirtualizerSw::releaseContext() {
207 if (mContext) {
208 mContext.reset();
209 }
210 return RetCode::SUCCESS;
211 }
212
213 // Processing method running in EffectWorker thread.
effectProcessImpl(float * in,float * out,int samples)214 IEffect::Status VirtualizerSw::effectProcessImpl(float* in, float* out, int samples) {
215 // TODO: get data buffer and process.
216 LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
217 for (int i = 0; i < samples; i++) {
218 *out++ = *in++;
219 }
220 return {STATUS_OK, samples, samples};
221 }
222
setVrStrength(int strength)223 RetCode VirtualizerSwContext::setVrStrength(int strength) {
224 mStrength = strength;
225 return RetCode::SUCCESS;
226 }
227
228 } // namespace aidl::android::hardware::audio::effect
229