1 /*
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>
19 #define LOG_TAG "AidlConversionSpatializer"
20 //#define LOG_NDEBUG 0
21
22 #include <aidl/android/hardware/audio/effect/DefaultExtension.h>
23 #include <aidl/android/hardware/audio/effect/VendorExtension.h>
24 #include <error/expected_utils.h>
25 #include <media/AidlConversionCppNdk.h>
26 #include <media/AidlConversionEffect.h>
27 #include <media/AidlConversionNdk.h>
28 #include <system/audio_effects/aidl_effects_utils.h>
29 #include <system/audio_effects/effect_spatializer.h>
30 #include <utils/Log.h>
31
32 #include "AidlConversionSpatializer.h"
33
34 namespace android {
35 namespace effect {
36
37 using aidl::android::getParameterSpecificField;
38 using aidl::android::aidl_utils::statusTFromBinderStatus;
39 using aidl::android::hardware::audio::common::SourceMetadata;
40 using aidl::android::hardware::audio::effect::DefaultExtension;
41 using aidl::android::hardware::audio::effect::Parameter;
42 using aidl::android::hardware::audio::effect::Range;
43 using aidl::android::hardware::audio::effect::Spatializer;
44 using aidl::android::hardware::audio::effect::VendorExtension;
45 using aidl::android::media::audio::common::AudioChannelLayout;
46 using aidl::android::media::audio::common::HeadTracking;
47 using aidl::android::media::audio::common::Spatialization;
48 using aidl::android::media::audio::common::toString;
49 using android::status_t;
50 using utils::EffectParamReader;
51 using utils::EffectParamWriter;
52
isSpatializerParameterSupported()53 bool 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
setParameter(EffectParamReader & param)70 status_t AidlConversionSpatializer::setParameter(EffectParamReader& param) {
71 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 aidlParam = MAKE_SPECIFIC_PARAMETER(Spatializer, spatializer, headTrackingSensorId,
146 sensorId);
147 return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
148 }
149 default: {
150 // 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;
156 }
157 }
158 } else {
159 aidlParam = VALUE_OR_RETURN_STATUS(
160 ::aidl::android::legacy2aidl_EffectParameterReader_Parameter(param));
161 }
162
163 return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
164 }
165
getParameter(EffectParamWriter & param)166 status_t AidlConversionSpatializer::getParameter(EffectParamWriter& param) {
167 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 }
174
175 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 std::vector<Spatialization::Level> levels;
183 for (const auto level : ::ndk::enum_range<Spatialization::Level>()) {
184 const auto spatializer =
185 Spatializer::make<Spatializer::spatializationLevel>(level);
186 if (spatializer >= range->min && spatializer <= range->max) {
187 levels.emplace_back(level);
188 }
189 }
190 const uint8_t num = levels.size();
191 RETURN_STATUS_IF_ERROR(param.writeToValue(&num));
192 for (const auto level : levels) {
193 RETURN_STATUS_IF_ERROR(param.writeToValue(&level));
194 }
195 return OK;
196 }
197 case SPATIALIZER_PARAM_LEVEL: {
198 Parameter aidlParam;
199 Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(Spatializer, spatializerTag,
200 Spatializer::spatializationLevel);
201 RETURN_STATUS_IF_ERROR(
202 statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
203 const auto level = VALUE_OR_RETURN_STATUS(GET_PARAMETER_SPECIFIC_FIELD(
204 aidlParam, Spatializer, spatializer, Spatializer::spatializationLevel,
205 Spatialization::Level));
206 return param.writeToValue(&level);
207 }
208 case SPATIALIZER_PARAM_HEADTRACKING_SUPPORTED: {
209 const auto& range = getRange<Range::spatializer, Range::SpatializerRange>(
210 mDesc.capability, Spatializer::spatializationLevel);
211 if (!range) {
212 ALOGE("%s %d: range not defined for spatializationLevel", __func__, __LINE__);
213 return BAD_VALUE;
214 }
215 const auto& nonSupport = Spatializer::make<Spatializer::spatializationLevel>(
216 Spatialization::Level::NONE);
217 const bool support = (range->min > range->max ||
218 (range->min == nonSupport && range->max == nonSupport))
219 ? false
220 : true;
221 return param.writeToValue(&support);
222 }
223 case SPATIALIZER_PARAM_HEADTRACKING_MODE: {
224 Parameter aidlParam;
225 Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(Spatializer, spatializerTag,
226 Spatializer::headTrackingMode);
227 RETURN_STATUS_IF_ERROR(
228 statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
229 const auto mode = VALUE_OR_RETURN_STATUS(GET_PARAMETER_SPECIFIC_FIELD(
230 aidlParam, Spatializer, spatializer, Spatializer::headTrackingMode,
231 HeadTracking::Mode));
232 return param.writeToValue(&mode);
233 }
234 case SPATIALIZER_PARAM_SUPPORTED_CHANNEL_MASKS: {
235 Parameter aidlParam;
236 Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(Spatializer, spatializerTag,
237 Spatializer::supportedChannelLayout);
238 RETURN_STATUS_IF_ERROR(
239 statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
240 const auto& supportedLayouts = VALUE_OR_RETURN_STATUS(GET_PARAMETER_SPECIFIC_FIELD(
241 aidlParam, Spatializer, spatializer, Spatializer::supportedChannelLayout,
242 std::vector<AudioChannelLayout>));
243 // audio_channel_mask_t is uint32_t enum, write number in 32bit
244 const uint32_t num = supportedLayouts.size();
245 RETURN_STATUS_IF_ERROR(param.writeToValue(&num));
246 for (const auto& layout : supportedLayouts) {
247 audio_channel_mask_t mask = VALUE_OR_RETURN_STATUS(
248 ::aidl::android::aidl2legacy_AudioChannelLayout_audio_channel_mask_t(
249 layout, false /* isInput */));
250 RETURN_STATUS_IF_ERROR(param.writeToValue(&mask));
251 }
252 return OK;
253 }
254 case SPATIALIZER_PARAM_SUPPORTED_SPATIALIZATION_MODES: {
255 const auto& range = getRange<Range::spatializer, Range::SpatializerRange>(
256 mDesc.capability, Spatializer::spatializationMode);
257 if (!range) {
258 return BAD_VALUE;
259 }
260 std::vector<Spatialization::Mode> modes;
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 modes.emplace_back(mode);
266 }
267 }
268 const uint8_t num = modes.size();
269 RETURN_STATUS_IF_ERROR(param.writeToValue(&num));
270 for (const auto mode : modes) {
271 RETURN_STATUS_IF_ERROR(param.writeToValue(&mode));
272 }
273 return OK;
274 }
275 case SPATIALIZER_PARAM_SUPPORTED_HEADTRACKING_CONNECTION: {
276 const auto& range = getRange<Range::spatializer, Range::SpatializerRange>(
277 mDesc.capability, Spatializer::headTrackingConnectionMode);
278 if (!range) {
279 return BAD_VALUE;
280 }
281 std::vector<HeadTracking::ConnectionMode> modes;
282 for (const auto mode : ::ndk::enum_range<HeadTracking::ConnectionMode>()) {
283 if (const auto spatializer =
284 Spatializer::make<Spatializer::headTrackingConnectionMode>(mode);
285 spatializer < range->min || spatializer > range->max) {
286 modes.emplace_back(mode);
287 }
288 }
289 const uint8_t num = modes.size();
290 RETURN_STATUS_IF_ERROR(param.writeToValue(&num));
291 for (const auto mode : modes) {
292 RETURN_STATUS_IF_ERROR(param.writeToValue(&mode));
293 }
294 return OK;
295 }
296 case SPATIALIZER_PARAM_HEADTRACKING_CONNECTION: {
297 status_t status = OK;
298 Parameter aidlParam;
299 Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(
300 Spatializer, spatializerTag, Spatializer::headTrackingConnectionMode);
301 RETURN_STATUS_IF_ERROR(
302 statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
303 const auto mode = VALUE_OR_RETURN_STATUS(GET_PARAMETER_SPECIFIC_FIELD(
304 aidlParam, Spatializer, spatializer,
305 Spatializer::headTrackingConnectionMode, HeadTracking::ConnectionMode));
306
307 id = MAKE_SPECIFIC_PARAMETER_ID(Spatializer, spatializerTag,
308 Spatializer::headTrackingSensorId);
309 RETURN_STATUS_IF_ERROR(
310 statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
311 const auto sensorId = VALUE_OR_RETURN_STATUS(
312 GET_PARAMETER_SPECIFIC_FIELD(aidlParam, Spatializer, spatializer,
313 Spatializer::headTrackingSensorId, int32_t));
314 uint32_t modeInt32 = static_cast<int32_t>(mode);
315 if (status = param.writeToValue(&modeInt32); status != OK) {
316 ALOGW("%s %d: write mode %s to value failed %d", __func__, __LINE__,
317 toString(mode).c_str(), status);
318 return status;
319 }
320 if (status = param.writeToValue(&sensorId); status != OK) {
321 ALOGW("%s %d: write sensorId %d to value failed %d", __func__, __LINE__,
322 sensorId, status);
323 return status;
324 }
325 return OK;
326 }
327 default: {
328 VENDOR_EXTENSION_GET_AND_RETURN(Spatializer, spatializer, param);
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 // copy the AIDL extension data back to effect_param_t
347 return VALUE_OR_RETURN_STATUS(
348 ::aidl::android::aidl2legacy_Parameter_EffectParameterWriter(aidlParam, param));
349 }
350 }
351
352 } // namespace effect
353 } // namespace android
354