blob: d1794f091b13631785d8e649ce8bf100ccfba00f [file] [log] [blame]
Shunkai Yao242521c2023-01-29 18:08:09 +00001/*
2 * Copyright (C) 2023 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 <cstdint>
18#include <cstring>
Shunkai Yao242521c2023-01-29 18:08:09 +000019#define LOG_TAG "AidlConversionSpatializer"
20//#define LOG_NDEBUG 0
21
Shunkai Yaoda4a6402023-03-03 19:38:17 +000022#include <aidl/android/hardware/audio/effect/DefaultExtension.h>
23#include <aidl/android/hardware/audio/effect/VendorExtension.h>
Shunkai Yao242521c2023-01-29 18:08:09 +000024#include <error/expected_utils.h>
Shunkai Yaoec116bf2024-02-13 01:57:36 +000025#include <media/AidlConversionCppNdk.h>
Shunkai Yao242521c2023-01-29 18:08:09 +000026#include <media/AidlConversionEffect.h>
Shunkai Yaoec116bf2024-02-13 01:57:36 +000027#include <media/AidlConversionNdk.h>
28#include <system/audio_effects/aidl_effects_utils.h>
Shunkai Yao242521c2023-01-29 18:08:09 +000029#include <system/audio_effects/effect_spatializer.h>
Shunkai Yao242521c2023-01-29 18:08:09 +000030#include <utils/Log.h>
31
32#include "AidlConversionSpatializer.h"
33
34namespace android {
35namespace effect {
36
Shunkai Yaoec116bf2024-02-13 01:57:36 +000037using aidl::android::getParameterSpecificField;
38using aidl::android::aidl_utils::statusTFromBinderStatus;
39using aidl::android::hardware::audio::common::SourceMetadata;
40using aidl::android::hardware::audio::effect::DefaultExtension;
41using aidl::android::hardware::audio::effect::Parameter;
42using aidl::android::hardware::audio::effect::Range;
43using aidl::android::hardware::audio::effect::Spatializer;
44using aidl::android::hardware::audio::effect::VendorExtension;
45using aidl::android::media::audio::common::AudioChannelLayout;
46using aidl::android::media::audio::common::HeadTracking;
47using aidl::android::media::audio::common::Spatialization;
48using aidl::android::media::audio::common::toString;
49using android::status_t;
Shunkai Yao242521c2023-01-29 18:08:09 +000050using utils::EffectParamReader;
51using utils::EffectParamWriter;
52
Shunkai Yaoec116bf2024-02-13 01:57:36 +000053bool AidlConversionSpatializer::isSpatializerParameterSupported() {
54 return mIsSpatializerAidlParamSupported.value_or(
55 (mIsSpatializerAidlParamSupported =
56 [&]() {
57 ::aidl::android::hardware::audio::effect::Parameter aidlParam;
58 auto id = MAKE_SPECIFIC_PARAMETER_ID(Spatializer, spatializerTag,
59 Spatializer::vendor);
60 // No range defined in descriptor capability means no Spatializer AIDL
61 // implementation BAD_VALUE return from getParameter indicates the
62 // parameter is not supported by HAL
63 return mDesc.capability.range.getTag() == Range::spatializer &&
64 mEffect->getParameter(id, &aidlParam).getStatus() !=
65 android::BAD_VALUE;
66 }())
67 .value());
68}
69
Shunkai Yao242521c2023-01-29 18:08:09 +000070status_t AidlConversionSpatializer::setParameter(EffectParamReader& param) {
Shunkai Yaoec116bf2024-02-13 01:57:36 +000071 Parameter aidlParam;
72 if (isSpatializerParameterSupported()) {
73 uint32_t command = 0;
74 if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(int8_t)) ||
75 OK != param.readFromParameter(&command)) {
76 ALOGE("%s %d invalid param %s", __func__, __LINE__, param.toString().c_str());
77 return BAD_VALUE;
78 }
79
80 switch (command) {
81 case SPATIALIZER_PARAM_LEVEL: {
82 Spatialization::Level level = Spatialization::Level::NONE;
83 if (OK != param.readFromValue(&level)) {
84 ALOGE("%s invalid level value %s", __func__, param.toString().c_str());
85 return BAD_VALUE;
86 }
87 aidlParam = MAKE_SPECIFIC_PARAMETER(Spatializer, spatializer,
88 spatializationLevel, level);
89 break;
90 }
91 case SPATIALIZER_PARAM_HEADTRACKING_MODE: {
92 HeadTracking::Mode mode = HeadTracking::Mode::DISABLED;
93 if (OK != param.readFromValue(&mode)) {
94 ALOGE("%s invalid mode value %s", __func__, param.toString().c_str());
95 return BAD_VALUE;
96 }
97 aidlParam = MAKE_SPECIFIC_PARAMETER(Spatializer, spatializer, headTrackingMode,
98 mode);
99 break;
100 }
101 case SPATIALIZER_PARAM_HEAD_TO_STAGE: {
102 const size_t valueSize = param.getValueSize();
103 if (valueSize / sizeof(float) > 6 || valueSize % sizeof(float) != 0) {
104 ALOGE("%s invalid parameter value size %zu", __func__, valueSize);
105 return BAD_VALUE;
106 }
107 std::array<float, 6> headToStage = {};
108 for (size_t i = 0; i < valueSize / sizeof(float); i++) {
109 if (OK != param.readFromValue(&headToStage[i])) {
110 ALOGE("%s failed to read headToStage from %s", __func__,
111 param.toString().c_str());
112 return BAD_VALUE;
113 }
114 }
115 HeadTracking::SensorData sensorData =
116 HeadTracking::SensorData::make<HeadTracking::SensorData::headToStage>(
117 headToStage);
118 aidlParam = MAKE_SPECIFIC_PARAMETER(Spatializer, spatializer,
119 headTrackingSensorData, sensorData);
120 break;
121 }
122 case SPATIALIZER_PARAM_HEADTRACKING_CONNECTION: {
123 int32_t modeInt32 = 0;
124 int32_t sensorId = -1;
125 if (OK != param.readFromValue(&modeInt32) || OK != param.readFromValue(&sensorId)) {
126 ALOGE("%s %d invalid parameter value %s", __func__, __LINE__,
127 param.toString().c_str());
128 return BAD_VALUE;
129 }
130
131 const auto mode = static_cast<HeadTracking::ConnectionMode>(modeInt32);
132 if (mode < *ndk::enum_range<HeadTracking::ConnectionMode>().begin() ||
133 mode > *ndk::enum_range<HeadTracking::ConnectionMode>().end()) {
134 ALOGE("%s %d invalid mode %d", __func__, __LINE__, modeInt32);
135 return BAD_VALUE;
136 }
137 aidlParam = MAKE_SPECIFIC_PARAMETER(Spatializer, spatializer,
138 headTrackingConnectionMode, mode);
139 if (status_t status = statusTFromBinderStatus(mEffect->setParameter(aidlParam));
140 status != OK) {
141 ALOGE("%s failed to set headTrackingConnectionMode %s", __func__,
142 toString(mode).c_str());
143 return status;
144 }
145 ALOGI("%s %d: %s", __func__, __LINE__, aidlParam.toString().c_str());
146 aidlParam = MAKE_SPECIFIC_PARAMETER(Spatializer, spatializer, headTrackingSensorId,
147 sensorId);
148 ALOGI("%s %d: %s", __func__, __LINE__, aidlParam.toString().c_str());
149 return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
150 }
151 default: {
152 ALOGE("%s %d invalid command %u", __func__, __LINE__, command);
153 return BAD_VALUE;
154 }
155 }
156 } else {
157 aidlParam = VALUE_OR_RETURN_STATUS(
158 ::aidl::android::legacy2aidl_EffectParameterReader_Parameter(param));
159 }
160
161 ALOGI("%s %d: %s", __func__, __LINE__, aidlParam.toString().c_str());
Shunkai Yao242521c2023-01-29 18:08:09 +0000162 return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
163}
164
165status_t AidlConversionSpatializer::getParameter(EffectParamWriter& param) {
Shunkai Yaoec116bf2024-02-13 01:57:36 +0000166 if (isSpatializerParameterSupported()) {
167 uint32_t command = 0;
168 if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(int8_t)) ||
169 OK != param.readFromParameter(&command)) {
170 ALOGE("%s %d invalid param %s", __func__, __LINE__, param.toString().c_str());
171 return BAD_VALUE;
172 }
Shunkai Yaoda4a6402023-03-03 19:38:17 +0000173
Shunkai Yaoec116bf2024-02-13 01:57:36 +0000174 switch (command) {
175 case SPATIALIZER_PARAM_SUPPORTED_LEVELS: {
176 const auto& range = getRange<Range::spatializer, Range::SpatializerRange>(
177 mDesc.capability, Spatializer::spatializationLevel);
178 if (!range) {
179 return BAD_VALUE;
180 }
181 for (const auto level : ::ndk::enum_range<Spatialization::Level>()) {
182 const auto spatializer =
183 Spatializer::make<Spatializer::spatializationLevel>(level);
184 if (spatializer >= range->min && spatializer <= range->max) {
185 if (status_t status = param.writeToValue(&level); status != OK) {
186 ALOGI("%s %d: write level %s to value failed %d", __func__, __LINE__,
187 toString(level).c_str(), status);
188 return status;
189 }
190 }
191 }
192 return OK;
193 }
194 case SPATIALIZER_PARAM_LEVEL: {
195 Parameter aidlParam;
196 Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(Spatializer, spatializerTag,
197 Spatializer::spatializationLevel);
198 RETURN_STATUS_IF_ERROR(
199 statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
200 const auto level = VALUE_OR_RETURN_STATUS(GET_PARAMETER_SPECIFIC_FIELD(
201 aidlParam, Spatializer, spatializer, Spatializer::spatializationLevel,
202 Spatialization::Level));
203 ALOGI("%s %d: %s", __func__, __LINE__, aidlParam.toString().c_str());
204 return param.writeToValue(&level);
205 }
206 case SPATIALIZER_PARAM_HEADTRACKING_SUPPORTED: {
207 const auto& range = getRange<Range::spatializer, Range::SpatializerRange>(
208 mDesc.capability, Spatializer::spatializationLevel);
209 if (!range) {
210 ALOGE("%s %d: range not defined for spatializationLevel", __func__, __LINE__);
211 return BAD_VALUE;
212 }
213 const auto& nonSupport = Spatializer::make<Spatializer::spatializationLevel>(
214 Spatialization::Level::NONE);
215 const bool support = (range->min > range->max ||
216 (range->min == nonSupport && range->max == nonSupport))
217 ? false
218 : true;
219 return param.writeToValue(&support);
220 }
221 case SPATIALIZER_PARAM_HEADTRACKING_MODE: {
222 Parameter aidlParam;
223 Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(Spatializer, spatializerTag,
224 Spatializer::headTrackingMode);
225 RETURN_STATUS_IF_ERROR(
226 statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
227 const auto mode = VALUE_OR_RETURN_STATUS(GET_PARAMETER_SPECIFIC_FIELD(
228 aidlParam, Spatializer, spatializer, Spatializer::headTrackingMode,
229 HeadTracking::Mode));
230 ALOGI("%s %d: %s", __func__, __LINE__, aidlParam.toString().c_str());
231 return param.writeToValue(&mode);
232 }
233 case SPATIALIZER_PARAM_SUPPORTED_CHANNEL_MASKS: {
234 Parameter aidlParam;
235 Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(Spatializer, spatializerTag,
236 Spatializer::supportedChannelLayout);
237 RETURN_STATUS_IF_ERROR(
238 statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
239 const auto& supportedLayouts = VALUE_OR_RETURN_STATUS(GET_PARAMETER_SPECIFIC_FIELD(
240 aidlParam, Spatializer, spatializer, Spatializer::supportedChannelLayout,
241 std::vector<AudioChannelLayout>));
242 for (const auto& layout : supportedLayouts) {
243 audio_channel_mask_t mask = VALUE_OR_RETURN_STATUS(
244 ::aidl::android::aidl2legacy_AudioChannelLayout_audio_channel_mask_t(
245 layout, false /* isInput */));
246 if (status_t status = param.writeToValue(&mask); status != OK) {
247 ALOGI("%s %d: write mask %s to value failed %d", __func__, __LINE__,
248 layout.toString().c_str(), status);
249 return status;
250 }
251 }
252 ALOGI("%s %d: %s", __func__, __LINE__, aidlParam.toString().c_str());
253 return OK;
254 }
255 case SPATIALIZER_PARAM_SUPPORTED_SPATIALIZATION_MODES: {
256 const auto& range = getRange<Range::spatializer, Range::SpatializerRange>(
257 mDesc.capability, Spatializer::spatializationMode);
258 if (!range) {
259 return BAD_VALUE;
260 }
261 for (const auto mode : ::ndk::enum_range<Spatialization::Mode>()) {
262 if (const auto spatializer =
263 Spatializer::make<Spatializer::spatializationMode>(mode);
264 spatializer >= range->min && spatializer <= range->max) {
265 if (status_t status = param.writeToValue(&mode); status != OK) {
266 ALOGI("%s %d: write mode %s to value failed %d", __func__, __LINE__,
267 toString(mode).c_str(), status);
268 return status;
269 }
270 }
271 }
272 return OK;
273 }
274 case SPATIALIZER_PARAM_SUPPORTED_HEADTRACKING_CONNECTION: {
275 const auto& range = getRange<Range::spatializer, Range::SpatializerRange>(
276 mDesc.capability, Spatializer::headTrackingConnectionMode);
277 if (!range) {
278 return BAD_VALUE;
279 }
280 for (const auto mode : ::ndk::enum_range<HeadTracking::ConnectionMode>()) {
281 if (const auto spatializer =
282 Spatializer::make<Spatializer::headTrackingConnectionMode>(mode);
283 spatializer < range->min || spatializer > range->max) {
284 continue;
285 }
286 if (status_t status = param.writeToValue(&mode); status != OK) {
287 ALOGI("%s %d: write mode %s to value failed %d", __func__, __LINE__,
288 toString(mode).c_str(), status);
289 return status;
290 }
291 }
292 return OK;
293 }
294 case SPATIALIZER_PARAM_HEADTRACKING_CONNECTION: {
295 status_t status = OK;
296 Parameter aidlParam;
297 Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(
298 Spatializer, spatializerTag, Spatializer::headTrackingConnectionMode);
299 RETURN_STATUS_IF_ERROR(
300 statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
301 const auto mode = VALUE_OR_RETURN_STATUS(GET_PARAMETER_SPECIFIC_FIELD(
302 aidlParam, Spatializer, spatializer,
303 Spatializer::headTrackingConnectionMode, HeadTracking::ConnectionMode));
304
305 id = MAKE_SPECIFIC_PARAMETER_ID(Spatializer, spatializerTag,
306 Spatializer::headTrackingSensorId);
307 RETURN_STATUS_IF_ERROR(
308 statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
309 const auto sensorId = VALUE_OR_RETURN_STATUS(
310 GET_PARAMETER_SPECIFIC_FIELD(aidlParam, Spatializer, spatializer,
311 Spatializer::headTrackingSensorId, int32_t));
312 uint32_t modeInt32 = static_cast<int32_t>(mode);
313 if (status = param.writeToValue(&modeInt32); status != OK) {
314 ALOGI("%s %d: write mode %s to value failed %d", __func__, __LINE__,
315 toString(mode).c_str(), status);
316 return status;
317 }
318 if (status = param.writeToValue(&sensorId); status != OK) {
319 ALOGI("%s %d: write sensorId %d to value failed %d", __func__, __LINE__,
320 sensorId, status);
321 return status;
322 }
323 ALOGI("%s %d: %s", __func__, __LINE__, aidlParam.toString().c_str());
324 return OK;
325 }
326 default: {
327 ALOGE("%s %d invalid command %u", __func__, __LINE__, command);
328 return BAD_VALUE;
329 }
330 }
331 } else {
332 Parameter aidlParam;
333 DefaultExtension defaultExt;
334 // read parameters into DefaultExtension vector<uint8_t>
335 defaultExt.bytes.resize(param.getParameterSize());
336 if (OK != param.readFromParameter(defaultExt.bytes.data(), param.getParameterSize())) {
337 ALOGE("%s %d invalid param %s", __func__, __LINE__, param.toString().c_str());
338 param.setStatus(BAD_VALUE);
339 return BAD_VALUE;
340 }
341
342 VendorExtension idTag;
343 idTag.extension.setParcelable(defaultExt);
344 Parameter::Id id = UNION_MAKE(Parameter::Id, vendorEffectTag, idTag);
345 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
346 ALOGI("%s %d: %s", __func__, __LINE__,
347 aidlParam.get<Parameter::specific>().toString().c_str());
348 // copy the AIDL extension data back to effect_param_t
349 return VALUE_OR_RETURN_STATUS(
350 ::aidl::android::aidl2legacy_Parameter_EffectParameterWriter(aidlParam, param));
351 }
Shunkai Yao242521c2023-01-29 18:08:09 +0000352}
353
354} // namespace effect
355} // namespace android