blob: 4282085a69e85656eb3cb2babd33e2550a99d775 [file] [log] [blame]
Mikhail Naganov3b5572e2024-11-08 16:48:28 -08001/*
2 * Copyright (C) 2024 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
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +000017#include <inttypes.h>
18
19#include <unordered_set>
20
21#define LOG_TAG "AHAL_Config"
22#include <android-base/logging.h>
23#include <android-base/strings.h>
Mikhail Naganov3b5572e2024-11-08 16:48:28 -080024#include <android/binder_enums.h>
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +000025
26#include <aidl/android/media/audio/common/AudioPort.h>
27#include <aidl/android/media/audio/common/AudioPortConfig.h>
28#include <media/AidlConversionCppNdk.h>
29#include <media/TypeConverter.h>
François Gaffie57ccab72024-04-17 11:47:51 +020030#include <media/convert.h>
31#include <utils/FastStrcmp.h>
32
33#include <Utils.h>
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +000034
35#include "core-impl/XmlConverter.h"
36#include "core-impl/XsdcConversion.h"
37
François Gaffie57ccab72024-04-17 11:47:51 +020038using aidl::android::hardware::audio::common::iequals;
39using aidl::android::hardware::audio::common::isValidAudioMode;
François Gaffie57ccab72024-04-17 11:47:51 +020040using aidl::android::hardware::audio::common::kValidAudioModes;
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +000041using aidl::android::media::audio::common::AudioChannelLayout;
François Gaffie57ccab72024-04-17 11:47:51 +020042using aidl::android::media::audio::common::AudioContentType;
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +000043using aidl::android::media::audio::common::AudioDevice;
44using aidl::android::media::audio::common::AudioDeviceAddress;
45using aidl::android::media::audio::common::AudioDeviceDescription;
46using aidl::android::media::audio::common::AudioDeviceType;
47using aidl::android::media::audio::common::AudioFormatDescription;
48using aidl::android::media::audio::common::AudioFormatType;
49using aidl::android::media::audio::common::AudioGain;
50using aidl::android::media::audio::common::AudioHalCapCriterion;
51using aidl::android::media::audio::common::AudioHalCapCriterionType;
François Gaffie57ccab72024-04-17 11:47:51 +020052using aidl::android::media::audio::common::AudioHalCapCriterionV2;
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +000053using aidl::android::media::audio::common::AudioHalVolumeCurve;
54using aidl::android::media::audio::common::AudioIoFlags;
François Gaffie57ccab72024-04-17 11:47:51 +020055using aidl::android::media::audio::common::AudioMode;
56using aidl::android::media::audio::common::AudioPolicyForcedConfig;
57using aidl::android::media::audio::common::AudioPolicyForceUse;
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +000058using aidl::android::media::audio::common::AudioPort;
59using aidl::android::media::audio::common::AudioPortConfig;
60using aidl::android::media::audio::common::AudioPortDeviceExt;
61using aidl::android::media::audio::common::AudioPortExt;
62using aidl::android::media::audio::common::AudioPortMixExt;
63using aidl::android::media::audio::common::AudioProfile;
François Gaffie57ccab72024-04-17 11:47:51 +020064using aidl::android::media::audio::common::AudioSource;
65using aidl::android::media::audio::common::AudioStreamType;
66using aidl::android::media::audio::common::AudioUsage;
Mikhail Naganov3b5572e2024-11-08 16:48:28 -080067using android::BAD_VALUE;
68using android::base::unexpected;
69using android::utilities::convertTo;
70using ndk::enum_range;
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +000071
72namespace ap_xsd = android::audio::policy::configuration;
73namespace eng_xsd = android::audio::policy::engine::configuration;
74
75namespace aidl::android::hardware::audio::core::internal {
76
François Gaffie57ccab72024-04-17 11:47:51 +020077static constexpr const char kXsdcForceConfigForCommunication[] = "ForceUseForCommunication";
78static constexpr const char kXsdcForceConfigForMedia[] = "ForceUseForMedia";
79static constexpr const char kXsdcForceConfigForRecord[] = "ForceUseForRecord";
80static constexpr const char kXsdcForceConfigForDock[] = "ForceUseForDock";
81static constexpr const char kXsdcForceConfigForSystem[] = "ForceUseForSystem";
82static constexpr const char kXsdcForceConfigForHdmiSystemAudio[] = "ForceUseForHdmiSystemAudio";
83static constexpr const char kXsdcForceConfigForEncodedSurround[] = "ForceUseForEncodedSurround";
84static constexpr const char kXsdcForceConfigForVibrateRinging[] = "ForceUseForVibrateRinging";
85
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +000086inline ConversionResult<std::string> assertNonEmpty(const std::string& s) {
87 if (s.empty()) {
88 LOG(ERROR) << __func__ << " Review Audio Policy config: "
89 << " empty string is not valid.";
90 return unexpected(BAD_VALUE);
91 }
92 return s;
93}
94
95#define NON_EMPTY_STRING_OR_FATAL(s) VALUE_OR_FATAL(assertNonEmpty(s))
96
François Gaffie57ccab72024-04-17 11:47:51 +020097ConversionResult<int32_t> convertAudioFlagsToAidl(
98 const std::vector<eng_xsd::FlagType>& xsdcFlagTypeVec) {
99 int legacyFlagMask = 0;
100 for (const eng_xsd::FlagType& xsdcFlagType : xsdcFlagTypeVec) {
101 if (xsdcFlagType != eng_xsd::FlagType::AUDIO_FLAG_NONE) {
102 audio_flags_mask_t legacyFlag = AUDIO_FLAG_NONE;
103 if (!::android::AudioFlagConverter::fromString(eng_xsd::toString(xsdcFlagType),
104 legacyFlag)) {
105 LOG(ERROR) << __func__ << " Review Audio Policy config, "
106 << eng_xsd::toString(xsdcFlagType) << " is not a valid flag.";
107 return unexpected(BAD_VALUE);
108 }
109 legacyFlagMask |= static_cast<int>(legacyFlag);
110 }
111 }
112 ConversionResult<int32_t> result = legacy2aidl_audio_flags_mask_t_int32_t_mask(
113 static_cast<audio_flags_mask_t>(legacyFlagMask));
114 if (!result.ok()) {
115 LOG(ERROR) << __func__ << " Review Audio Policy config, " << legacyFlagMask
116 << " has invalid flag(s).";
117 return unexpected(BAD_VALUE);
118 }
119 return result;
120}
121
122ConversionResult<AudioStreamType> convertAudioStreamTypeToAidl(const eng_xsd::Stream& xsdcStream) {
123 audio_stream_type_t legacyStreamType;
124 if (!::android::StreamTypeConverter::fromString(eng_xsd::toString(xsdcStream),
125 legacyStreamType)) {
126 LOG(ERROR) << __func__ << " Review Audio Policy config, " << eng_xsd::toString(xsdcStream)
127 << " is not a valid audio stream type.";
128 return unexpected(BAD_VALUE);
129 }
130 ConversionResult<AudioStreamType> result =
131 legacy2aidl_audio_stream_type_t_AudioStreamType(legacyStreamType);
132 if (!result.ok()) {
133 LOG(ERROR) << __func__ << " Review Audio Policy config, " << legacyStreamType
134 << " is not a valid audio stream type.";
135 return unexpected(BAD_VALUE);
136 }
137 return result;
138}
139
140ConversionResult<AudioSource> convertAudioSourceToAidl(
141 const eng_xsd::SourceEnumType& xsdcSourceType) {
142 audio_source_t legacySourceType;
143 if (!::android::SourceTypeConverter::fromString(eng_xsd::toString(xsdcSourceType),
144 legacySourceType)) {
145 LOG(ERROR) << __func__ << " Review Audio Policy config, "
146 << eng_xsd::toString(xsdcSourceType) << " is not a valid audio source.";
147 return unexpected(BAD_VALUE);
148 }
149 ConversionResult<AudioSource> result = legacy2aidl_audio_source_t_AudioSource(legacySourceType);
150 if (!result.ok()) {
151 LOG(ERROR) << __func__ << " Review Audio Policy config, " << legacySourceType
152 << " is not a valid audio source.";
153 return unexpected(BAD_VALUE);
154 }
155 return result;
156}
157
158ConversionResult<AudioContentType> convertAudioContentTypeToAidl(
159 const eng_xsd::ContentType& xsdcContentType) {
160 audio_content_type_t legacyContentType;
161 if (!::android::AudioContentTypeConverter::fromString(eng_xsd::toString(xsdcContentType),
162 legacyContentType)) {
163 LOG(ERROR) << __func__ << " Review Audio Policy config, "
164 << eng_xsd::toString(xsdcContentType) << " is not a valid audio content type.";
165 return unexpected(BAD_VALUE);
166 }
167 ConversionResult<AudioContentType> result =
168 legacy2aidl_audio_content_type_t_AudioContentType(legacyContentType);
169 if (!result.ok()) {
170 LOG(ERROR) << __func__ << " Review Audio Policy config, " << legacyContentType
171 << " is not a valid audio content type.";
172 return unexpected(BAD_VALUE);
173 }
174 return result;
175}
176
177ConversionResult<AudioUsage> convertAudioUsageToAidl(const eng_xsd::UsageEnumType& xsdcUsage) {
178 audio_usage_t legacyUsage;
179 if (!::android::UsageTypeConverter::fromString(eng_xsd::toString(xsdcUsage), legacyUsage)) {
180 LOG(ERROR) << __func__ << " Review Audio Policy config, not a valid audio usage.";
181 return unexpected(BAD_VALUE);
182 }
183 ConversionResult<AudioUsage> result = legacy2aidl_audio_usage_t_AudioUsage(legacyUsage);
184 if (!result.ok()) {
185 LOG(ERROR) << __func__ << " Review Audio Policy config, not a valid audio usage.";
186 return unexpected(BAD_VALUE);
187 }
188 return result;
189}
190
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000191ConversionResult<AudioFormatDescription> convertAudioFormatToAidl(const std::string& xsdcFormat) {
192 audio_format_t legacyFormat = ::android::formatFromString(xsdcFormat, AUDIO_FORMAT_DEFAULT);
193 ConversionResult<AudioFormatDescription> result =
194 legacy2aidl_audio_format_t_AudioFormatDescription(legacyFormat);
195 if ((legacyFormat == AUDIO_FORMAT_DEFAULT && xsdcFormat.compare("AUDIO_FORMAT_DEFAULT") != 0) ||
196 !result.ok()) {
197 LOG(ERROR) << __func__ << " Review Audio Policy config: " << xsdcFormat
198 << " is not a valid audio format.";
199 return unexpected(BAD_VALUE);
200 }
201 return result;
202}
203
204std::unordered_set<std::string> getAttachedDevices(const ap_xsd::Modules::Module& moduleConfig) {
205 std::unordered_set<std::string> attachedDeviceSet;
206 if (moduleConfig.hasAttachedDevices()) {
207 for (const ap_xsd::AttachedDevices& attachedDevices : moduleConfig.getAttachedDevices()) {
208 if (attachedDevices.hasItem()) {
209 attachedDeviceSet.insert(attachedDevices.getItem().begin(),
210 attachedDevices.getItem().end());
211 }
212 }
213 }
214 return attachedDeviceSet;
215}
216
217ConversionResult<AudioDeviceDescription> convertDeviceTypeToAidl(const std::string& xType) {
218 audio_devices_t legacyDeviceType = AUDIO_DEVICE_NONE;
219 ::android::DeviceConverter::fromString(xType, legacyDeviceType);
220 ConversionResult<AudioDeviceDescription> result =
221 legacy2aidl_audio_devices_t_AudioDeviceDescription(legacyDeviceType);
222 if ((legacyDeviceType == AUDIO_DEVICE_NONE) || !result.ok()) {
223 LOG(ERROR) << __func__ << " Review Audio Policy config: " << xType
224 << " is not a valid device type.";
225 return unexpected(BAD_VALUE);
226 }
227 return result;
228}
229
230ConversionResult<AudioDevice> createAudioDevice(
231 const ap_xsd::DevicePorts::DevicePort& xDevicePort) {
232 AudioDevice device = {
233 .type = VALUE_OR_FATAL(convertDeviceTypeToAidl(xDevicePort.getType())),
234 .address = xDevicePort.hasAddress()
235 ? AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(
236 xDevicePort.getAddress())
237 : AudioDeviceAddress{}};
238 if (device.type.type == AudioDeviceType::IN_MICROPHONE && device.type.connection.empty()) {
239 device.address = "bottom";
240 } else if (device.type.type == AudioDeviceType::IN_MICROPHONE_BACK &&
241 device.type.connection.empty()) {
242 device.address = "back";
243 }
244 return device;
245}
246
247ConversionResult<AudioPortExt> createAudioPortExt(
248 const ap_xsd::DevicePorts::DevicePort& xDevicePort,
249 const std::string& xDefaultOutputDevice) {
250 AudioPortDeviceExt deviceExt = {
251 .device = VALUE_OR_FATAL(createAudioDevice(xDevicePort)),
252 .flags = (xDevicePort.getTagName() == xDefaultOutputDevice)
253 ? 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE
254 : 0,
255 .encodedFormats =
256 xDevicePort.hasEncodedFormats()
257 ? VALUE_OR_FATAL(
258 (convertCollectionToAidl<std::string, AudioFormatDescription>(
259 xDevicePort.getEncodedFormats(),
260 &convertAudioFormatToAidl)))
261 : std::vector<AudioFormatDescription>{},
262 };
263 return AudioPortExt::make<AudioPortExt::Tag::device>(deviceExt);
264}
265
266ConversionResult<AudioPortExt> createAudioPortExt(const ap_xsd::MixPorts::MixPort& xMixPort) {
267 AudioPortMixExt mixExt = {
268 .maxOpenStreamCount =
269 xMixPort.hasMaxOpenCount() ? static_cast<int>(xMixPort.getMaxOpenCount()) : 0,
270 .maxActiveStreamCount = xMixPort.hasMaxActiveCount()
271 ? static_cast<int>(xMixPort.getMaxActiveCount())
272 : 1,
273 .recommendedMuteDurationMs =
274 xMixPort.hasRecommendedMuteDurationMs()
275 ? static_cast<int>(xMixPort.getRecommendedMuteDurationMs())
276 : 0};
277 return AudioPortExt::make<AudioPortExt::Tag::mix>(mixExt);
278}
279
280ConversionResult<int> convertGainModeToAidl(const std::vector<ap_xsd::AudioGainMode>& gainModeVec) {
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000281 int gainModeMask = 0;
282 for (const ap_xsd::AudioGainMode& gainMode : gainModeVec) {
Mikhail Naganovcc21b6f2023-10-17 19:39:27 -0700283 audio_gain_mode_t legacyGainMode;
284 if (::android::GainModeConverter::fromString(ap_xsd::toString(gainMode), legacyGainMode)) {
285 gainModeMask |= static_cast<int>(legacyGainMode);
286 }
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000287 }
288 return gainModeMask;
289}
290
291ConversionResult<AudioChannelLayout> convertChannelMaskToAidl(
292 const ap_xsd::AudioChannelMask& xChannelMask) {
293 std::string xChannelMaskLiteral = ap_xsd::toString(xChannelMask);
294 audio_channel_mask_t legacyChannelMask = ::android::channelMaskFromString(xChannelMaskLiteral);
295 ConversionResult<AudioChannelLayout> result =
296 legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
297 legacyChannelMask,
298 /* isInput= */ xChannelMaskLiteral.find("AUDIO_CHANNEL_IN_") == 0);
299 if ((legacyChannelMask == AUDIO_CHANNEL_INVALID) || !result.ok()) {
300 LOG(ERROR) << __func__ << " Review Audio Policy config: " << xChannelMaskLiteral
301 << " is not a valid audio channel mask.";
302 return unexpected(BAD_VALUE);
303 }
304 return result;
305}
306
307ConversionResult<AudioGain> convertGainToAidl(const ap_xsd::Gains::Gain& xGain) {
308 return AudioGain{
309 .mode = VALUE_OR_FATAL(convertGainModeToAidl(xGain.getMode())),
310 .channelMask =
311 xGain.hasChannel_mask()
312 ? VALUE_OR_FATAL(convertChannelMaskToAidl(xGain.getChannel_mask()))
313 : AudioChannelLayout{},
314 .minValue = xGain.hasMinValueMB() ? xGain.getMinValueMB() : 0,
315 .maxValue = xGain.hasMaxValueMB() ? xGain.getMaxValueMB() : 0,
316 .defaultValue = xGain.hasDefaultValueMB() ? xGain.getDefaultValueMB() : 0,
317 .stepValue = xGain.hasStepValueMB() ? xGain.getStepValueMB() : 0,
318 .minRampMs = xGain.hasMinRampMs() ? xGain.getMinRampMs() : 0,
319 .maxRampMs = xGain.hasMaxRampMs() ? xGain.getMaxRampMs() : 0,
320 .useForVolume = xGain.hasUseForVolume() ? xGain.getUseForVolume() : false,
321 };
322}
323
324ConversionResult<AudioProfile> convertAudioProfileToAidl(const ap_xsd::Profile& xProfile) {
325 return AudioProfile{
326 .format = xProfile.hasFormat()
327 ? VALUE_OR_FATAL(convertAudioFormatToAidl(xProfile.getFormat()))
328 : AudioFormatDescription{},
329 .channelMasks =
330 xProfile.hasChannelMasks()
331 ? VALUE_OR_FATAL((convertCollectionToAidl<ap_xsd::AudioChannelMask,
332 AudioChannelLayout>(
333 xProfile.getChannelMasks(), &convertChannelMaskToAidl)))
334 : std::vector<AudioChannelLayout>{},
335 .sampleRates = xProfile.hasSamplingRates()
336 ? VALUE_OR_FATAL((convertCollectionToAidl<int64_t, int>(
337 xProfile.getSamplingRates(),
338 [](const int64_t x) -> int { return x; })))
339 : std::vector<int>{}};
340}
341
342ConversionResult<AudioIoFlags> convertIoFlagsToAidl(
343 const std::vector<ap_xsd::AudioInOutFlag>& flags, const ap_xsd::Role role,
344 bool flagsForMixPort) {
Mikhail Naganov37fe9e82023-11-28 17:07:23 -0800345 int legacyFlagMask = 0;
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000346 if ((role == ap_xsd::Role::sink && flagsForMixPort) ||
347 (role == ap_xsd::Role::source && !flagsForMixPort)) {
348 for (const ap_xsd::AudioInOutFlag& flag : flags) {
Mikhail Naganovcc21b6f2023-10-17 19:39:27 -0700349 audio_input_flags_t legacyFlag;
350 if (::android::InputFlagConverter::fromString(ap_xsd::toString(flag), legacyFlag)) {
Mikhail Naganov37fe9e82023-11-28 17:07:23 -0800351 legacyFlagMask |= static_cast<int>(legacyFlag);
Mikhail Naganovcc21b6f2023-10-17 19:39:27 -0700352 }
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000353 }
Mikhail Naganov37fe9e82023-11-28 17:07:23 -0800354 return AudioIoFlags::make<AudioIoFlags::Tag::input>(
355 VALUE_OR_FATAL(legacy2aidl_audio_input_flags_t_int32_t_mask(
356 static_cast<audio_input_flags_t>(legacyFlagMask))));
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000357 } else {
358 for (const ap_xsd::AudioInOutFlag& flag : flags) {
Mikhail Naganovcc21b6f2023-10-17 19:39:27 -0700359 audio_output_flags_t legacyFlag;
360 if (::android::OutputFlagConverter::fromString(ap_xsd::toString(flag), legacyFlag)) {
Mikhail Naganov37fe9e82023-11-28 17:07:23 -0800361 legacyFlagMask |= static_cast<int>(legacyFlag);
Mikhail Naganovcc21b6f2023-10-17 19:39:27 -0700362 }
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000363 }
Mikhail Naganov37fe9e82023-11-28 17:07:23 -0800364 return AudioIoFlags::make<AudioIoFlags::Tag::output>(
365 VALUE_OR_FATAL(legacy2aidl_audio_output_flags_t_int32_t_mask(
366 static_cast<audio_output_flags_t>(legacyFlagMask))));
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000367 }
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000368}
369
370ConversionResult<AudioPort> convertDevicePortToAidl(
371 const ap_xsd::DevicePorts::DevicePort& xDevicePort, const std::string& xDefaultOutputDevice,
372 int32_t& nextPortId) {
373 return AudioPort{
374 .id = nextPortId++,
375 .name = NON_EMPTY_STRING_OR_FATAL(xDevicePort.getTagName()),
376 .profiles = VALUE_OR_FATAL((convertCollectionToAidl<ap_xsd::Profile, AudioProfile>(
377 xDevicePort.getProfile(), convertAudioProfileToAidl))),
378 .flags = VALUE_OR_FATAL(convertIoFlagsToAidl({}, xDevicePort.getRole(), false)),
379 .gains = VALUE_OR_FATAL(
380 (convertWrappedCollectionToAidl<ap_xsd::Gains, ap_xsd::Gains::Gain, AudioGain>(
381 xDevicePort.getGains(), &ap_xsd::Gains::getGain, convertGainToAidl))),
382
383 .ext = VALUE_OR_FATAL(createAudioPortExt(xDevicePort, xDefaultOutputDevice))};
384}
385
386ConversionResult<std::vector<AudioPort>> convertDevicePortsInModuleToAidl(
387 const ap_xsd::Modules::Module& xModuleConfig, int32_t& nextPortId) {
388 std::vector<AudioPort> audioPortVec;
389 std::vector<ap_xsd::DevicePorts> xDevicePortsVec = xModuleConfig.getDevicePorts();
390 if (xDevicePortsVec.size() > 1) {
391 LOG(ERROR) << __func__ << "Having multiple '<devicePorts>' elements is not allowed, found: "
392 << xDevicePortsVec.size();
393 return unexpected(BAD_VALUE);
394 }
395 if (!xDevicePortsVec.empty()) {
396 const std::string xDefaultOutputDevice = xModuleConfig.hasDefaultOutputDevice()
397 ? xModuleConfig.getDefaultOutputDevice()
398 : "";
399 audioPortVec.reserve(xDevicePortsVec[0].getDevicePort().size());
400 for (const ap_xsd::DevicePorts& xDevicePortsType : xDevicePortsVec) {
401 for (const ap_xsd::DevicePorts::DevicePort& xDevicePort :
402 xDevicePortsType.getDevicePort()) {
403 audioPortVec.push_back(VALUE_OR_FATAL(
404 convertDevicePortToAidl(xDevicePort, xDefaultOutputDevice, nextPortId)));
405 }
406 }
407 }
408 const std::unordered_set<std::string> xAttachedDeviceSet = getAttachedDevices(xModuleConfig);
409 for (const auto& port : audioPortVec) {
410 const auto& devicePort = port.ext.get<AudioPortExt::device>();
411 if (xAttachedDeviceSet.count(port.name) != devicePort.device.type.connection.empty()) {
412 LOG(ERROR) << __func__ << ": Review Audio Policy config: <attachedDevices> "
413 << "list is incorrect or devicePort \"" << port.name
414 << "\" type= " << devicePort.device.type.toString() << " is incorrect.";
415 return unexpected(BAD_VALUE);
416 }
417 }
418 return audioPortVec;
419}
420
421ConversionResult<AudioPort> convertMixPortToAidl(const ap_xsd::MixPorts::MixPort& xMixPort,
422 int32_t& nextPortId) {
423 return AudioPort{
424 .id = nextPortId++,
425 .name = NON_EMPTY_STRING_OR_FATAL(xMixPort.getName()),
426 .profiles = VALUE_OR_FATAL((convertCollectionToAidl<ap_xsd::Profile, AudioProfile>(
427 xMixPort.getProfile(), convertAudioProfileToAidl))),
428 .flags = xMixPort.hasFlags()
429 ? VALUE_OR_FATAL(convertIoFlagsToAidl(xMixPort.getFlags(),
430 xMixPort.getRole(), true))
431 : VALUE_OR_FATAL(convertIoFlagsToAidl({}, xMixPort.getRole(), true)),
432 .gains = VALUE_OR_FATAL(
433 (convertWrappedCollectionToAidl<ap_xsd::Gains, ap_xsd::Gains::Gain, AudioGain>(
434 xMixPort.getGains(), &ap_xsd::Gains::getGain, &convertGainToAidl))),
435 .ext = VALUE_OR_FATAL(createAudioPortExt(xMixPort)),
436 };
437}
438
439ConversionResult<std::vector<AudioPort>> convertMixPortsInModuleToAidl(
440 const ap_xsd::Modules::Module& xModuleConfig, int32_t& nextPortId) {
441 std::vector<AudioPort> audioPortVec;
442 std::vector<ap_xsd::MixPorts> xMixPortsVec = xModuleConfig.getMixPorts();
443 if (xMixPortsVec.size() > 1) {
444 LOG(ERROR) << __func__ << "Having multiple '<mixPorts>' elements is not allowed, found: "
445 << xMixPortsVec.size();
446 return unexpected(BAD_VALUE);
447 }
448 if (!xMixPortsVec.empty()) {
449 audioPortVec.reserve(xMixPortsVec[0].getMixPort().size());
450 for (const ap_xsd::MixPorts& xMixPortsType : xMixPortsVec) {
451 for (const ap_xsd::MixPorts::MixPort& xMixPort : xMixPortsType.getMixPort()) {
452 audioPortVec.push_back(VALUE_OR_FATAL(convertMixPortToAidl(xMixPort, nextPortId)));
453 }
454 }
455 }
456 return audioPortVec;
457}
458
459ConversionResult<int32_t> getSinkPortId(const ap_xsd::Routes::Route& xRoute,
460 const std::unordered_map<std::string, int32_t>& portMap) {
461 auto portMapIter = portMap.find(xRoute.getSink());
462 if (portMapIter == portMap.end()) {
463 LOG(ERROR) << __func__ << " Review Audio Policy config: audio route"
464 << "has sink: " << xRoute.getSink()
465 << " which is neither a device port nor mix port.";
466 return unexpected(BAD_VALUE);
467 }
468 return portMapIter->second;
469}
470
471ConversionResult<std::vector<int32_t>> getSourcePortIds(
472 const ap_xsd::Routes::Route& xRoute,
473 const std::unordered_map<std::string, int32_t>& portMap) {
474 std::vector<int32_t> sourcePortIds;
475 for (const std::string& rawSource : ::android::base::Split(xRoute.getSources(), ",")) {
476 const std::string source = ::android::base::Trim(rawSource);
477 auto portMapIter = portMap.find(source);
478 if (portMapIter == portMap.end()) {
479 LOG(ERROR) << __func__ << " Review Audio Policy config: audio route"
480 << "has source \"" << source
481 << "\" which is neither a device port nor mix port.";
482 return unexpected(BAD_VALUE);
483 }
484 sourcePortIds.push_back(portMapIter->second);
485 }
486 return sourcePortIds;
487}
488
489ConversionResult<AudioRoute> convertRouteToAidl(const ap_xsd::Routes::Route& xRoute,
490 const std::vector<AudioPort>& aidlAudioPorts) {
491 std::unordered_map<std::string, int32_t> portMap;
492 for (const AudioPort& port : aidlAudioPorts) {
493 portMap.insert({port.name, port.id});
494 }
495 return AudioRoute{.sourcePortIds = VALUE_OR_FATAL(getSourcePortIds(xRoute, portMap)),
496 .sinkPortId = VALUE_OR_FATAL(getSinkPortId(xRoute, portMap)),
497 .isExclusive = (xRoute.getType() == ap_xsd::MixType::mux)};
498}
499
500ConversionResult<std::vector<AudioRoute>> convertRoutesInModuleToAidl(
501 const ap_xsd::Modules::Module& xModuleConfig,
502 const std::vector<AudioPort>& aidlAudioPorts) {
503 std::vector<AudioRoute> audioRouteVec;
504 std::vector<ap_xsd::Routes> xRoutesVec = xModuleConfig.getRoutes();
505 if (!xRoutesVec.empty()) {
506 /*
507 * xRoutesVec likely only contains one element; that is, it's
508 * likely that all ap_xsd::Routes::MixPort types that we need to convert
509 * are inside of xRoutesVec[0].
510 */
511 audioRouteVec.reserve(xRoutesVec[0].getRoute().size());
512 for (const ap_xsd::Routes& xRoutesType : xRoutesVec) {
513 for (const ap_xsd::Routes::Route& xRoute : xRoutesType.getRoute()) {
514 audioRouteVec.push_back(VALUE_OR_FATAL(convertRouteToAidl(xRoute, aidlAudioPorts)));
515 }
516 }
517 }
518 return audioRouteVec;
519}
520
521ConversionResult<std::unique_ptr<Module::Configuration>> convertModuleConfigToAidl(
522 const ap_xsd::Modules::Module& xModuleConfig) {
523 auto result = std::make_unique<Module::Configuration>();
524 auto& aidlModuleConfig = *result;
525 std::vector<AudioPort> devicePorts = VALUE_OR_FATAL(
526 convertDevicePortsInModuleToAidl(xModuleConfig, aidlModuleConfig.nextPortId));
527
528 // The XML config does not specify the default input device.
529 // Assign the first attached input device as the default.
530 for (auto& port : devicePorts) {
531 if (port.flags.getTag() != AudioIoFlags::input) continue;
532 auto& deviceExt = port.ext.get<AudioPortExt::device>();
533 if (!deviceExt.device.type.connection.empty()) continue;
534 deviceExt.flags |= 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
535 break;
536 }
537
538 std::vector<AudioPort> mixPorts = VALUE_OR_FATAL(
539 convertMixPortsInModuleToAidl(xModuleConfig, aidlModuleConfig.nextPortId));
540 aidlModuleConfig.ports.reserve(devicePorts.size() + mixPorts.size());
541 aidlModuleConfig.ports.insert(aidlModuleConfig.ports.end(), devicePorts.begin(),
542 devicePorts.end());
543 aidlModuleConfig.ports.insert(aidlModuleConfig.ports.end(), mixPorts.begin(), mixPorts.end());
544
545 aidlModuleConfig.routes =
546 VALUE_OR_FATAL(convertRoutesInModuleToAidl(xModuleConfig, aidlModuleConfig.ports));
547 return result;
548}
549
François Gaffie57ccab72024-04-17 11:47:51 +0200550ConversionResult<AudioMode> convertTelephonyModeToAidl(const std::string& xsdcModeCriterionType) {
551 const auto it = std::find_if(kValidAudioModes.begin(), kValidAudioModes.end(),
552 [&xsdcModeCriterionType](const auto& mode) {
553 return toString(mode) == xsdcModeCriterionType;
554 });
555 if (it == kValidAudioModes.end()) {
556 LOG(ERROR) << __func__ << " invalid mode " << xsdcModeCriterionType;
557 return unexpected(BAD_VALUE);
558 }
559 return *it;
560}
561
562ConversionResult<AudioDeviceAddress> convertDeviceAddressToAidl(const std::string& xsdcAddress) {
563 return AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(xsdcAddress);
564}
565
566ConversionResult<eng_xsd::CriterionTypeType> getCriterionTypeByName(
567 const std::string& name,
568 const std::vector<eng_xsd::CriterionTypesType>& xsdcCriterionTypesVec) {
569 for (const auto& xsdCriterionTypes : xsdcCriterionTypesVec) {
570 for (const auto& xsdcCriterionType : xsdCriterionTypes.getCriterion_type()) {
571 if (xsdcCriterionType.getName() == name) {
572 return xsdcCriterionType;
573 }
574 }
575 }
576 LOG(ERROR) << __func__ << " failed to find criterion type " << name;
577 return unexpected(BAD_VALUE);
578}
579
580ConversionResult<std::vector<std::optional<AudioHalCapCriterionV2>>>
581convertCapCriteriaCollectionToAidl(
582 const std::vector<eng_xsd::CriteriaType>& xsdcCriteriaVec,
583 const std::vector<eng_xsd::CriterionTypesType>& xsdcCriterionTypesVec) {
584 std::vector<std::optional<AudioHalCapCriterionV2>> resultAidlCriterionVec;
585 if (xsdcCriteriaVec.empty() || xsdcCriterionTypesVec.empty()) {
586 LOG(ERROR) << __func__ << " empty criteria/criterionTypes";
587 return unexpected(BAD_VALUE);
588 }
589 for (const auto& xsdCriteria : xsdcCriteriaVec) {
590 for (const auto& xsdcCriterion : xsdCriteria.getCriterion()) {
591 resultAidlCriterionVec.push_back(
592 std::optional<AudioHalCapCriterionV2>(VALUE_OR_FATAL(
593 convertCapCriterionV2ToAidl(xsdcCriterion, xsdcCriterionTypesVec))));
594 }
595 }
596 return resultAidlCriterionVec;
597}
598
599ConversionResult<std::vector<AudioDeviceDescription>> convertDevicesToAidl(
600 const eng_xsd::CriterionTypeType& xsdcDeviceCriterionType) {
601 if (xsdcDeviceCriterionType.getValues().empty()) {
602 LOG(ERROR) << __func__ << " no values provided";
603 return unexpected(BAD_VALUE);
604 }
605 std::vector<AudioDeviceDescription> aidlDevices;
606 for (eng_xsd::ValuesType xsdcValues : xsdcDeviceCriterionType.getValues()) {
607 aidlDevices.reserve(xsdcValues.getValue().size());
608 for (const eng_xsd::ValueType& xsdcValue : xsdcValues.getValue()) {
609 if (!xsdcValue.hasAndroid_type()) {
610 LOG(ERROR) << __func__ << " empty android type";
611 return unexpected(BAD_VALUE);
612 }
613 uint32_t integerValue;
614 if (!convertTo(xsdcValue.getAndroid_type(), integerValue)) {
615 LOG(ERROR) << __func__ << " failed to convert android type "
616 << xsdcValue.getAndroid_type();
617 return unexpected(BAD_VALUE);
618 }
619 aidlDevices.push_back(
620 VALUE_OR_RETURN(legacy2aidl_audio_devices_t_AudioDeviceDescription(
621 static_cast<audio_devices_t>(integerValue))));
622 }
623 }
624 return aidlDevices;
625}
626
627ConversionResult<std::vector<AudioDeviceAddress>> convertDeviceAddressesToAidl(
628 const eng_xsd::CriterionTypeType& xsdcDeviceAddressesCriterionType) {
629 if (xsdcDeviceAddressesCriterionType.getValues().empty()) {
630 LOG(ERROR) << __func__ << " no values provided";
631 return unexpected(BAD_VALUE);
632 }
633 std::vector<AudioDeviceAddress> aidlDeviceAddresses;
634 for (eng_xsd::ValuesType xsdcValues : xsdcDeviceAddressesCriterionType.getValues()) {
635 aidlDeviceAddresses.reserve(xsdcValues.getValue().size());
636 for (const eng_xsd::ValueType& xsdcValue : xsdcValues.getValue()) {
637 aidlDeviceAddresses.push_back(
638 AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(xsdcValue.getLiteral()));
639 }
640 }
641 return aidlDeviceAddresses;
642}
643
Mikhail Naganov3b5572e2024-11-08 16:48:28 -0800644ConversionResult<AudioMode> convertAudioModeToAidl(const std::string& xsdcAudioModeType) {
645 const auto it = std::find_if(enum_range<AudioMode>().begin(), enum_range<AudioMode>().end(),
646 [&](const auto v) { return toString(v) == xsdcAudioModeType; });
647 if (it == enum_range<AudioMode>().end()) {
648 LOG(ERROR) << __func__ << " invalid audio mode " << xsdcAudioModeType;
649 return unexpected(BAD_VALUE);
650 }
651 return *it;
652}
653
François Gaffie57ccab72024-04-17 11:47:51 +0200654ConversionResult<std::vector<AudioMode>> convertTelephonyModesToAidl(
655 const eng_xsd::CriterionTypeType& xsdcTelephonyModeCriterionType) {
656 if (xsdcTelephonyModeCriterionType.getValues().empty()) {
657 LOG(ERROR) << __func__ << " no values provided";
658 return unexpected(BAD_VALUE);
659 }
660 std::vector<AudioMode> aidlAudioModes;
661 for (eng_xsd::ValuesType xsdcValues : xsdcTelephonyModeCriterionType.getValues()) {
662 aidlAudioModes.reserve(xsdcValues.getValue().size());
663 for (const eng_xsd::ValueType& xsdcValue : xsdcValues.getValue()) {
Mikhail Naganov3b5572e2024-11-08 16:48:28 -0800664 aidlAudioModes.push_back(
665 VALUE_OR_RETURN(convertAudioModeToAidl(xsdcValue.getLiteral())));
François Gaffie57ccab72024-04-17 11:47:51 +0200666 }
667 }
668 return aidlAudioModes;
669}
670
Mikhail Naganov3b5572e2024-11-08 16:48:28 -0800671ConversionResult<std::vector<AudioPolicyForceUse>> convertForceUseConfigsToAidl(
672 const std::string& criterionValue,
François Gaffie57ccab72024-04-17 11:47:51 +0200673 const eng_xsd::CriterionTypeType& xsdcForcedConfigCriterionType) {
674 if (xsdcForcedConfigCriterionType.getValues().empty()) {
675 LOG(ERROR) << __func__ << " no values provided";
676 return unexpected(BAD_VALUE);
677 }
Mikhail Naganov3b5572e2024-11-08 16:48:28 -0800678 std::vector<AudioPolicyForceUse> aidlForcedConfigs;
François Gaffie57ccab72024-04-17 11:47:51 +0200679 for (eng_xsd::ValuesType xsdcValues : xsdcForcedConfigCriterionType.getValues()) {
680 aidlForcedConfigs.reserve(xsdcValues.getValue().size());
681 for (const eng_xsd::ValueType& xsdcValue : xsdcValues.getValue()) {
Mikhail Naganov3b5572e2024-11-08 16:48:28 -0800682 aidlForcedConfigs.push_back(
683 VALUE_OR_RETURN(convertForceUseToAidl(criterionValue, xsdcValue.getLiteral())));
François Gaffie57ccab72024-04-17 11:47:51 +0200684 }
685 }
686 return aidlForcedConfigs;
687}
688
Mikhail Naganov3b5572e2024-11-08 16:48:28 -0800689template <typename T>
690ConversionResult<T> convertForceUseForcedConfigToAidl(
691 const std::string& xsdcForcedConfigCriterionType) {
692 const auto it = std::find_if(enum_range<T>().begin(), enum_range<T>().end(), [&](const auto v) {
693 return toString(v) == xsdcForcedConfigCriterionType;
694 });
695 if (it == enum_range<T>().end()) {
696 LOG(ERROR) << __func__ << " invalid forced config " << xsdcForcedConfigCriterionType;
697 return unexpected(BAD_VALUE);
698 }
699 return *it;
700}
701
702ConversionResult<AudioPolicyForceUse> convertForceUseToAidl(const std::string& xsdcCriterionName,
703 const std::string& xsdcCriterionValue) {
François Gaffie57ccab72024-04-17 11:47:51 +0200704 if (!fastcmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForCommunication,
Mikhail Naganov3b5572e2024-11-08 16:48:28 -0800705 strlen(kXsdcForceConfigForCommunication))) {
706 const auto deviceCategory = VALUE_OR_RETURN(
707 convertForceUseForcedConfigToAidl<AudioPolicyForceUse::CommunicationDeviceCategory>(
708 xsdcCriterionValue));
709 return AudioPolicyForceUse::make<AudioPolicyForceUse::forCommunication>(deviceCategory);
François Gaffie57ccab72024-04-17 11:47:51 +0200710 }
711 if (!fasticmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForMedia,
712 strlen(kXsdcForceConfigForMedia))) {
Mikhail Naganov3b5572e2024-11-08 16:48:28 -0800713 const auto deviceCategory = VALUE_OR_RETURN(
714 convertForceUseForcedConfigToAidl<AudioPolicyForceUse::MediaDeviceCategory>(
715 xsdcCriterionValue));
716 return AudioPolicyForceUse::make<AudioPolicyForceUse::forMedia>(deviceCategory);
François Gaffie57ccab72024-04-17 11:47:51 +0200717 }
718 if (!fasticmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForRecord,
719 strlen(kXsdcForceConfigForRecord))) {
Mikhail Naganov3b5572e2024-11-08 16:48:28 -0800720 const auto deviceCategory = VALUE_OR_RETURN(
721 convertForceUseForcedConfigToAidl<AudioPolicyForceUse::CommunicationDeviceCategory>(
722 xsdcCriterionValue));
723 return AudioPolicyForceUse::make<AudioPolicyForceUse::forRecord>(deviceCategory);
François Gaffie57ccab72024-04-17 11:47:51 +0200724 }
725 if (!fasticmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForDock,
Mikhail Naganov3b5572e2024-11-08 16:48:28 -0800726 strlen(kXsdcForceConfigForDock))) {
727 const auto dockType =
728 VALUE_OR_RETURN(convertForceUseForcedConfigToAidl<AudioPolicyForceUse::DockType>(
729 xsdcCriterionValue));
730 return AudioPolicyForceUse::make<AudioPolicyForceUse::dock>(dockType);
François Gaffie57ccab72024-04-17 11:47:51 +0200731 }
732 if (!fasticmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForSystem,
733 strlen(kXsdcForceConfigForSystem))) {
Mikhail Naganov3b5572e2024-11-08 16:48:28 -0800734 return AudioPolicyForceUse::make<AudioPolicyForceUse::systemSounds>(xsdcCriterionValue ==
735 "SYSTEM_ENFORCED");
François Gaffie57ccab72024-04-17 11:47:51 +0200736 }
737 if (!fasticmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForHdmiSystemAudio,
738 strlen(kXsdcForceConfigForHdmiSystemAudio))) {
Mikhail Naganov3b5572e2024-11-08 16:48:28 -0800739 return AudioPolicyForceUse::make<AudioPolicyForceUse::hdmiSystemAudio>(
740 xsdcCriterionValue == "HDMI_SYSTEM_AUDIO_ENFORCED");
François Gaffie57ccab72024-04-17 11:47:51 +0200741 }
742 if (!fasticmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForEncodedSurround,
743 strlen(kXsdcForceConfigForEncodedSurround))) {
Mikhail Naganov3b5572e2024-11-08 16:48:28 -0800744 const auto encodedSurround = VALUE_OR_RETURN(
745 convertForceUseForcedConfigToAidl<AudioPolicyForceUse::EncodedSurroundConfig>(
746 xsdcCriterionValue));
747 return AudioPolicyForceUse::make<AudioPolicyForceUse::encodedSurround>(encodedSurround);
François Gaffie57ccab72024-04-17 11:47:51 +0200748 }
749 if (!fasticmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForVibrateRinging,
750 strlen(kXsdcForceConfigForVibrateRinging))) {
Mikhail Naganov3b5572e2024-11-08 16:48:28 -0800751 const auto deviceCategory = VALUE_OR_RETURN(
752 convertForceUseForcedConfigToAidl<AudioPolicyForceUse::CommunicationDeviceCategory>(
753 xsdcCriterionValue));
754 return AudioPolicyForceUse::make<AudioPolicyForceUse::forVibrateRinging>(deviceCategory);
François Gaffie57ccab72024-04-17 11:47:51 +0200755 }
756 LOG(ERROR) << __func__ << " unrecognized force use " << xsdcCriterionName;
757 return unexpected(BAD_VALUE);
758}
759
760ConversionResult<AudioHalCapCriterionV2> convertCapCriterionV2ToAidl(
761 const eng_xsd::CriterionType& xsdcCriterion,
762 const std::vector<eng_xsd::CriterionTypesType>& xsdcCriterionTypesVec) {
763 eng_xsd::CriterionTypeType xsdcCriterionType =
764 VALUE_OR_RETURN(getCriterionTypeByName(xsdcCriterion.getType(), xsdcCriterionTypesVec));
765 std::string defaultLiteralValue =
766 xsdcCriterion.has_default() ? xsdcCriterion.get_default() : "";
767 using Tag = AudioHalCapCriterionV2::Tag;
768 if (iequals(xsdcCriterion.getName(), toString(Tag::availableInputDevices))) {
769 return AudioHalCapCriterionV2::make<Tag::availableInputDevices>(
770 VALUE_OR_RETURN(convertDevicesToAidl(xsdcCriterionType)));
771 }
772 if (iequals(xsdcCriterion.getName(), toString(Tag::availableOutputDevices))) {
773 return AudioHalCapCriterionV2::make<Tag::availableOutputDevices>(
774 VALUE_OR_RETURN(convertDevicesToAidl(xsdcCriterionType)));
775 }
776 if (iequals(xsdcCriterion.getName(), toString(Tag::availableInputDevicesAddresses))) {
777 return AudioHalCapCriterionV2::make<Tag::availableInputDevicesAddresses>(
778 VALUE_OR_RETURN(convertDeviceAddressesToAidl(xsdcCriterionType)));
779 }
780 if (iequals(xsdcCriterion.getName(), toString(Tag::availableOutputDevicesAddresses))) {
781 return AudioHalCapCriterionV2::make<Tag::availableOutputDevicesAddresses>(
782 VALUE_OR_RETURN(convertDeviceAddressesToAidl(xsdcCriterionType)));
783 }
784 if (iequals(xsdcCriterion.getName(), toString(Tag::telephonyMode))) {
785 return AudioHalCapCriterionV2::make<Tag::telephonyMode>(
786 VALUE_OR_RETURN(convertTelephonyModesToAidl(xsdcCriterionType)));
787 }
788 if (!fastcmp<strncmp>(xsdcCriterion.getName().c_str(), kXsdcForceConfigForUse,
789 strlen(kXsdcForceConfigForUse))) {
Mikhail Naganov3b5572e2024-11-08 16:48:28 -0800790 return AudioHalCapCriterionV2::make<Tag::forceConfigForUse>(VALUE_OR_RETURN(
791 convertForceUseConfigsToAidl(xsdcCriterion.getName(), xsdcCriterionType)));
François Gaffie57ccab72024-04-17 11:47:51 +0200792 }
793 LOG(ERROR) << __func__ << " unrecognized criterion " << xsdcCriterion.getName();
794 return unexpected(BAD_VALUE);
795}
796
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000797ConversionResult<AudioHalCapCriterion> convertCapCriterionToAidl(
798 const eng_xsd::CriterionType& xsdcCriterion) {
799 AudioHalCapCriterion aidlCapCriterion;
800 aidlCapCriterion.name = xsdcCriterion.getName();
801 aidlCapCriterion.criterionTypeName = xsdcCriterion.getType();
François Gaffie57ccab72024-04-17 11:47:51 +0200802 aidlCapCriterion.defaultLiteralValue =
803 xsdcCriterion.has_default() ? xsdcCriterion.get_default() : "";
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000804 return aidlCapCriterion;
805}
806
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000807ConversionResult<AudioHalVolumeCurve::CurvePoint> convertCurvePointToAidl(
808 const std::string& xsdcCurvePoint) {
809 AudioHalVolumeCurve::CurvePoint aidlCurvePoint{};
810 if ((sscanf(xsdcCurvePoint.c_str(), "%" SCNd8 ",%d", &aidlCurvePoint.index,
811 &aidlCurvePoint.attenuationMb) != 2) ||
812 (aidlCurvePoint.index < AudioHalVolumeCurve::CurvePoint::MIN_INDEX) ||
813 (aidlCurvePoint.index > AudioHalVolumeCurve::CurvePoint::MAX_INDEX)) {
814 LOG(ERROR) << __func__ << " Review Audio Policy config: volume curve point:"
815 << "\"" << xsdcCurvePoint << "\" is invalid";
816 return unexpected(BAD_VALUE);
817 }
818 return aidlCurvePoint;
819}
820} // namespace aidl::android::hardware::audio::core::internal