blob: a88ef83d9325fe407aacf17b666812731f9c7134 [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 }
Shunkai Yaoec116bf2024-02-13 01:57:36 +0000145 aidlParam = MAKE_SPECIFIC_PARAMETER(Spatializer, spatializer, headTrackingSensorId,
146 sensorId);
Shunkai Yaoec116bf2024-02-13 01:57:36 +0000147 return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
148 }
149 default: {
Shunkai Yao271a14d2024-04-05 16:26:47 +0000150 // for vendor extension, copy data area to the DefaultExtension, parameter ignored
151 VendorExtension ext = VALUE_OR_RETURN_STATUS(
152 aidl::android::legacy2aidl_EffectParameterReader_VendorExtension(param));
153 aidlParam =
154 MAKE_SPECIFIC_PARAMETER(Spatializer, spatializer, vendor, ext);
155 break;
Shunkai Yaoec116bf2024-02-13 01:57:36 +0000156 }
157 }
158 } else {
159 aidlParam = VALUE_OR_RETURN_STATUS(
160 ::aidl::android::legacy2aidl_EffectParameterReader_Parameter(param));
161 }
162
Shunkai Yao242521c2023-01-29 18:08:09 +0000163 return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
164}
165
166status_t AidlConversionSpatializer::getParameter(EffectParamWriter& param) {
Shunkai Yaoec116bf2024-02-13 01:57:36 +0000167 if (isSpatializerParameterSupported()) {
168 uint32_t command = 0;
169 if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(int8_t)) ||
170 OK != param.readFromParameter(&command)) {
171 ALOGE("%s %d invalid param %s", __func__, __LINE__, param.toString().c_str());
172 return BAD_VALUE;
173 }
Shunkai Yaoda4a6402023-03-03 19:38:17 +0000174
Shunkai Yaoec116bf2024-02-13 01:57:36 +0000175 switch (command) {
176 case SPATIALIZER_PARAM_SUPPORTED_LEVELS: {
177 const auto& range = getRange<Range::spatializer, Range::SpatializerRange>(
178 mDesc.capability, Spatializer::spatializationLevel);
179 if (!range) {
180 return BAD_VALUE;
181 }
182 for (const auto level : ::ndk::enum_range<Spatialization::Level>()) {
183 const auto spatializer =
184 Spatializer::make<Spatializer::spatializationLevel>(level);
185 if (spatializer >= range->min && spatializer <= range->max) {
186 if (status_t status = param.writeToValue(&level); status != OK) {
Shunkai Yaoac61ee92024-03-14 21:57:46 +0000187 ALOGW("%s %d: write level %s to value failed %d", __func__, __LINE__,
Shunkai Yaoec116bf2024-02-13 01:57:36 +0000188 toString(level).c_str(), status);
189 return status;
190 }
191 }
192 }
193 return OK;
194 }
195 case SPATIALIZER_PARAM_LEVEL: {
196 Parameter aidlParam;
197 Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(Spatializer, spatializerTag,
198 Spatializer::spatializationLevel);
199 RETURN_STATUS_IF_ERROR(
200 statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
201 const auto level = VALUE_OR_RETURN_STATUS(GET_PARAMETER_SPECIFIC_FIELD(
202 aidlParam, Spatializer, spatializer, Spatializer::spatializationLevel,
203 Spatialization::Level));
Shunkai Yaoec116bf2024-02-13 01:57:36 +0000204 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));
Shunkai Yaoec116bf2024-02-13 01:57:36 +0000230 return param.writeToValue(&mode);
231 }
232 case SPATIALIZER_PARAM_SUPPORTED_CHANNEL_MASKS: {
233 Parameter aidlParam;
234 Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(Spatializer, spatializerTag,
235 Spatializer::supportedChannelLayout);
236 RETURN_STATUS_IF_ERROR(
237 statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
238 const auto& supportedLayouts = VALUE_OR_RETURN_STATUS(GET_PARAMETER_SPECIFIC_FIELD(
239 aidlParam, Spatializer, spatializer, Spatializer::supportedChannelLayout,
240 std::vector<AudioChannelLayout>));
241 for (const auto& layout : supportedLayouts) {
242 audio_channel_mask_t mask = VALUE_OR_RETURN_STATUS(
243 ::aidl::android::aidl2legacy_AudioChannelLayout_audio_channel_mask_t(
244 layout, false /* isInput */));
245 if (status_t status = param.writeToValue(&mask); status != OK) {
Shunkai Yaoac61ee92024-03-14 21:57:46 +0000246 ALOGW("%s %d: write mask %s to value failed %d", __func__, __LINE__,
Shunkai Yaoec116bf2024-02-13 01:57:36 +0000247 layout.toString().c_str(), status);
248 return status;
249 }
250 }
Shunkai Yaoec116bf2024-02-13 01:57:36 +0000251 return OK;
252 }
253 case SPATIALIZER_PARAM_SUPPORTED_SPATIALIZATION_MODES: {
254 const auto& range = getRange<Range::spatializer, Range::SpatializerRange>(
255 mDesc.capability, Spatializer::spatializationMode);
256 if (!range) {
257 return BAD_VALUE;
258 }
259 for (const auto mode : ::ndk::enum_range<Spatialization::Mode>()) {
260 if (const auto spatializer =
261 Spatializer::make<Spatializer::spatializationMode>(mode);
262 spatializer >= range->min && spatializer <= range->max) {
263 if (status_t status = param.writeToValue(&mode); status != OK) {
Shunkai Yaoac61ee92024-03-14 21:57:46 +0000264 ALOGW("%s %d: write mode %s to value failed %d", __func__, __LINE__,
Shunkai Yaoec116bf2024-02-13 01:57:36 +0000265 toString(mode).c_str(), status);
266 return status;
267 }
268 }
269 }
270 return OK;
271 }
272 case SPATIALIZER_PARAM_SUPPORTED_HEADTRACKING_CONNECTION: {
273 const auto& range = getRange<Range::spatializer, Range::SpatializerRange>(
274 mDesc.capability, Spatializer::headTrackingConnectionMode);
275 if (!range) {
276 return BAD_VALUE;
277 }
278 for (const auto mode : ::ndk::enum_range<HeadTracking::ConnectionMode>()) {
279 if (const auto spatializer =
280 Spatializer::make<Spatializer::headTrackingConnectionMode>(mode);
281 spatializer < range->min || spatializer > range->max) {
282 continue;
283 }
284 if (status_t status = param.writeToValue(&mode); status != OK) {
Shunkai Yaoac61ee92024-03-14 21:57:46 +0000285 ALOGW("%s %d: write mode %s to value failed %d", __func__, __LINE__,
286 toString(mode).c_str(), status);
Shunkai Yaoec116bf2024-02-13 01:57:36 +0000287 return status;
288 }
289 }
290 return OK;
291 }
292 case SPATIALIZER_PARAM_HEADTRACKING_CONNECTION: {
293 status_t status = OK;
294 Parameter aidlParam;
295 Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(
296 Spatializer, spatializerTag, Spatializer::headTrackingConnectionMode);
297 RETURN_STATUS_IF_ERROR(
298 statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
299 const auto mode = VALUE_OR_RETURN_STATUS(GET_PARAMETER_SPECIFIC_FIELD(
300 aidlParam, Spatializer, spatializer,
301 Spatializer::headTrackingConnectionMode, HeadTracking::ConnectionMode));
302
303 id = MAKE_SPECIFIC_PARAMETER_ID(Spatializer, spatializerTag,
304 Spatializer::headTrackingSensorId);
305 RETURN_STATUS_IF_ERROR(
306 statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
307 const auto sensorId = VALUE_OR_RETURN_STATUS(
308 GET_PARAMETER_SPECIFIC_FIELD(aidlParam, Spatializer, spatializer,
309 Spatializer::headTrackingSensorId, int32_t));
310 uint32_t modeInt32 = static_cast<int32_t>(mode);
311 if (status = param.writeToValue(&modeInt32); status != OK) {
Shunkai Yaoac61ee92024-03-14 21:57:46 +0000312 ALOGW("%s %d: write mode %s to value failed %d", __func__, __LINE__,
Shunkai Yaoec116bf2024-02-13 01:57:36 +0000313 toString(mode).c_str(), status);
314 return status;
315 }
316 if (status = param.writeToValue(&sensorId); status != OK) {
Shunkai Yaoac61ee92024-03-14 21:57:46 +0000317 ALOGW("%s %d: write sensorId %d to value failed %d", __func__, __LINE__,
Shunkai Yaoec116bf2024-02-13 01:57:36 +0000318 sensorId, status);
319 return status;
320 }
Shunkai Yaoec116bf2024-02-13 01:57:36 +0000321 return OK;
322 }
323 default: {
Shunkai Yao271a14d2024-04-05 16:26:47 +0000324 VENDOR_EXTENSION_GET_AND_RETURN(Spatializer, spatializer, param);
Shunkai Yaoec116bf2024-02-13 01:57:36 +0000325 }
326 }
327 } else {
328 Parameter aidlParam;
329 DefaultExtension defaultExt;
330 // read parameters into DefaultExtension vector<uint8_t>
331 defaultExt.bytes.resize(param.getParameterSize());
332 if (OK != param.readFromParameter(defaultExt.bytes.data(), param.getParameterSize())) {
333 ALOGE("%s %d invalid param %s", __func__, __LINE__, param.toString().c_str());
334 param.setStatus(BAD_VALUE);
335 return BAD_VALUE;
336 }
337
338 VendorExtension idTag;
339 idTag.extension.setParcelable(defaultExt);
340 Parameter::Id id = UNION_MAKE(Parameter::Id, vendorEffectTag, idTag);
341 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
Shunkai Yaoec116bf2024-02-13 01:57:36 +0000342 // copy the AIDL extension data back to effect_param_t
343 return VALUE_OR_RETURN_STATUS(
344 ::aidl::android::aidl2legacy_Parameter_EffectParameterWriter(aidlParam, param));
345 }
Shunkai Yao242521c2023-01-29 18:08:09 +0000346}
347
348} // namespace effect
349} // namespace android