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