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