blob: 6e7833c8d807b8baf4cb03be362dd64b0dbe4dcb [file] [log] [blame]
Shunkai Yao05b190a2022-12-22 00:21:31 +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_VisualizerLibEffects"
18
19#include <android-base/logging.h>
20#include "Visualizer.h"
21
22using aidl::android::hardware::audio::effect::Descriptor;
23using aidl::android::hardware::audio::effect::IEffect;
24using aidl::android::hardware::audio::effect::VisualizerImpl;
25using aidl::android::hardware::audio::effect::kVisualizerImplUUID;
26using aidl::android::hardware::audio::effect::State;
27using aidl::android::media::audio::common::AudioUuid;
28
29extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
30 std::shared_ptr<IEffect>* instanceSpp) {
31 if (!in_impl_uuid || *in_impl_uuid != kVisualizerImplUUID) {
32 LOG(ERROR) << __func__ << "uuid not supported";
33 return EX_ILLEGAL_ARGUMENT;
34 }
35 if (instanceSpp) {
36 *instanceSpp = ndk::SharedRefBase::make<VisualizerImpl>();
37 LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
38 return EX_NONE;
39 } else {
40 LOG(ERROR) << __func__ << " invalid input parameter!";
41 return EX_ILLEGAL_ARGUMENT;
42 }
43}
44
45extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
46 if (!in_impl_uuid || *in_impl_uuid != kVisualizerImplUUID) {
47 LOG(ERROR) << __func__ << "uuid not supported";
48 return EX_ILLEGAL_ARGUMENT;
49 }
50 *_aidl_return = VisualizerImpl::kDescriptor;
51 return EX_NONE;
52}
53
54namespace aidl::android::hardware::audio::effect {
55
56const std::string VisualizerImpl::kEffectName = "Visualizer";
Shunkai Yao6b857c92023-02-13 17:44:52 +000057const std::vector<Range::VisualizerRange> VisualizerImpl::kRanges = {
58 MAKE_RANGE(Visualizer, latencyMs, 0, VisualizerContext::kMaxLatencyMs),
59 MAKE_RANGE(Visualizer, captureSamples, 0, VisualizerContext::kMaxCaptureBufSize),
60 /* get only parameters, set invalid range (min > max) to indicate not support set */
61 MAKE_RANGE(Visualizer, measurement, Visualizer::Measurement({.peak = 1, .rms = 1}),
62 Visualizer::Measurement({.peak = 0, .rms = 0})),
63 MAKE_RANGE(Visualizer, captureSampleBuffer, std::vector<uint8_t>({1}),
64 std::vector<uint8_t>({0}))};
65const Capability VisualizerImpl::kCapability = {
66 .range = Range::make<Range::visualizer>(VisualizerImpl::kRanges)};
Shunkai Yao05b190a2022-12-22 00:21:31 +000067const Descriptor VisualizerImpl::kDescriptor = {
68 .common = {.id = {.type = kVisualizerTypeUUID,
69 .uuid = kVisualizerImplUUID,
70 .proxy = std::nullopt},
71 .flags = {.type = Flags::Type::INSERT,
72 .insert = Flags::Insert::LAST,
73 .volume = Flags::Volume::CTRL},
74 .name = VisualizerImpl::kEffectName,
75 .implementor = "The Android Open Source Project"},
Shunkai Yao6b857c92023-02-13 17:44:52 +000076 .capability = VisualizerImpl::kCapability};
Shunkai Yao05b190a2022-12-22 00:21:31 +000077
78ndk::ScopedAStatus VisualizerImpl::getDescriptor(Descriptor* _aidl_return) {
79 RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr");
80 LOG(DEBUG) << __func__ << kDescriptor.toString();
81 *_aidl_return = kDescriptor;
82 return ndk::ScopedAStatus::ok();
83}
84
85ndk::ScopedAStatus VisualizerImpl::commandImpl(CommandId command) {
86 RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
87 switch (command) {
88 case CommandId::START:
89 mContext->enable();
90 break;
91 case CommandId::STOP:
92 mContext->disable();
93 break;
94 case CommandId::RESET:
95 mContext->disable();
96 mContext->resetBuffer();
97 break;
98 default:
99 LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported";
100 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
101 "commandIdNotSupported");
102 }
103 return ndk::ScopedAStatus::ok();
104}
105
Shunkai Yao05b190a2022-12-22 00:21:31 +0000106ndk::ScopedAStatus VisualizerImpl::setParameterSpecific(const Parameter::Specific& specific) {
107 RETURN_IF(Parameter::Specific::visualizer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
108 "EffectNotSupported");
109 RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
110
111 auto& param = specific.get<Parameter::Specific::visualizer>();
Shunkai Yao6b857c92023-02-13 17:44:52 +0000112 RETURN_IF(!inRange(param, kRanges), EX_ILLEGAL_ARGUMENT, "outOfRange");
Shunkai Yao05b190a2022-12-22 00:21:31 +0000113 const auto tag = param.getTag();
114 switch (tag) {
115 case Visualizer::captureSamples: {
116 RETURN_IF(mContext->setCaptureSamples(param.get<Visualizer::captureSamples>()) !=
117 RetCode::SUCCESS,
118 EX_ILLEGAL_ARGUMENT, "setCaptureSizeFailed");
119 return ndk::ScopedAStatus::ok();
120 }
121 case Visualizer::scalingMode: {
122 RETURN_IF(mContext->setScalingMode(param.get<Visualizer::scalingMode>()) !=
123 RetCode::SUCCESS,
124 EX_ILLEGAL_ARGUMENT, "setScalingModeFailed");
125 return ndk::ScopedAStatus::ok();
126 }
127 case Visualizer::measurementMode: {
128 RETURN_IF(mContext->setMeasurementMode(param.get<Visualizer::measurementMode>()) !=
129 RetCode::SUCCESS,
130 EX_ILLEGAL_ARGUMENT, "setMeasurementModeFailed");
131 return ndk::ScopedAStatus::ok();
132 }
Shunkai Yao6b857c92023-02-13 17:44:52 +0000133 case Visualizer::latencyMs: {
134 RETURN_IF(mContext->setDownstreamLatency(param.get<Visualizer::latencyMs>()) !=
135 RetCode::SUCCESS,
136 EX_ILLEGAL_ARGUMENT, "setLatencyFailed");
137 return ndk::ScopedAStatus::ok();
Shunkai Yao05b190a2022-12-22 00:21:31 +0000138 }
139 default: {
140 LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
141 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
142 EX_ILLEGAL_ARGUMENT, "VisualizerTagNotSupported");
143 }
144 }
145}
146
Shunkai Yao05b190a2022-12-22 00:21:31 +0000147ndk::ScopedAStatus VisualizerImpl::getParameterSpecific(const Parameter::Id& id,
148 Parameter::Specific* specific) {
149 RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr");
150 auto tag = id.getTag();
151 RETURN_IF(Parameter::Id::visualizerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
152 auto specificId = id.get<Parameter::Id::visualizerTag>();
153 auto specificTag = specificId.getTag();
154 switch (specificTag) {
155 case Visualizer::Id::commonTag: {
156 return getParameterVisualizer(specificId.get<Visualizer::Id::commonTag>(), specific);
157 }
Shunkai Yao05b190a2022-12-22 00:21:31 +0000158 default: {
159 LOG(ERROR) << __func__ << " unsupported tag: " << toString(specificTag);
160 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
161 "VisualizerTagNotSupported");
162 }
163 }
164 return ndk::ScopedAStatus::ok();
165}
166
167ndk::ScopedAStatus VisualizerImpl::getParameterVisualizer(const Visualizer::Tag& tag,
168 Parameter::Specific* specific) {
169 RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
170
171 Visualizer param;
172 switch (tag) {
173 case Visualizer::captureSamples: {
174 param.set<Visualizer::captureSamples>(mContext->getCaptureSamples());
175 break;
176 }
177 case Visualizer::scalingMode: {
178 param.set<Visualizer::scalingMode>(mContext->getScalingMode());
179 break;
180 }
181 case Visualizer::measurementMode: {
182 param.set<Visualizer::measurementMode>(mContext->getMeasurementMode());
183 break;
184 }
Shunkai Yao6b857c92023-02-13 17:44:52 +0000185 case Visualizer::measurement: {
186 param.set<Visualizer::measurement>(mContext->getMeasure());
187 break;
188 }
189 case Visualizer::captureSampleBuffer: {
190 param.set<Visualizer::captureSampleBuffer>(mContext->capture());
191 break;
192 }
193 case Visualizer::latencyMs: {
194 param.set<Visualizer::latencyMs>(mContext->getDownstreamLatency());
195 break;
196 }
Shunkai Yao05b190a2022-12-22 00:21:31 +0000197 default: {
198 LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
199 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
200 EX_ILLEGAL_ARGUMENT, "VisualizerTagNotSupported");
201 }
202 }
203
204 specific->set<Parameter::Specific::visualizer>(param);
205 return ndk::ScopedAStatus::ok();
206}
207
208std::shared_ptr<EffectContext> VisualizerImpl::createContext(const Parameter::Common& common) {
209 if (mContext) {
210 LOG(DEBUG) << __func__ << " context already exist";
211 return mContext;
212 }
213
214 mContext = std::make_shared<VisualizerContext>(1 /* statusFmqDepth */, common);
215 mContext->initParams(common);
216 return mContext;
217}
218
219RetCode VisualizerImpl::releaseContext() {
220 if (mContext) {
221 mContext->disable();
222 mContext->resetBuffer();
223 }
224 return RetCode::SUCCESS;
225}
226
227// Processing method running in EffectWorker thread.
228IEffect::Status VisualizerImpl::effectProcessImpl(float* in, float* out, int samples) {
229 IEffect::Status status = {EX_NULL_POINTER, 0, 0};
230 RETURN_VALUE_IF(!mContext, status, "nullContext");
231 return mContext->process(in, out, samples);
232}
233
234} // namespace aidl::android::hardware::audio::effect