1 /*
2 * Copyright (C) 2022 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 <fcntl.h>
18 #include <inttypes.h>
19 #include <unistd.h>
20
21 #include <functional>
22 #include <unordered_map>
23
24 #define LOG_TAG "AHAL_ApmXmlConverter"
25 #include <android-base/logging.h>
26
27 #include <aidl/android/media/audio/common/AudioHalEngineConfig.h>
28 #include <media/stagefright/foundation/MediaDefs.h>
29 #include <system/audio-base-utils.h>
30
31 #include "core-impl/AidlConversionXsdc.h"
32 #include "core-impl/AudioPolicyConfigXmlConverter.h"
33
34 using aidl::android::media::audio::common::AudioFormatDescription;
35 using aidl::android::media::audio::common::AudioHalEngineConfig;
36 using aidl::android::media::audio::common::AudioHalVolumeCurve;
37 using aidl::android::media::audio::common::AudioHalVolumeGroup;
38 using aidl::android::media::audio::common::AudioStreamType;
39
40 namespace xsd = android::audio::policy::configuration;
41
42 namespace aidl::android::hardware::audio::core::internal {
43
44 static const int kDefaultVolumeIndexMin = 0;
45 static const int kDefaultVolumeIndexMax = 100;
46 static const int KVolumeIndexDeferredToAudioService = -1;
47 /**
48 * Valid curve points take the form "<index>,<attenuationMb>", where the index
49 * must be in the range [0,100]. kInvalidCurvePointIndex is used to indicate
50 * that a point was formatted incorrectly (e.g. if a vendor accidentally typed a
51 * '.' instead of a ',' in their XML) -- using such a curve point will result in
52 * failed VTS tests.
53 */
54 static const int8_t kInvalidCurvePointIndex = -1;
55
convertCurvePointToAidl(const std::string & xsdcCurvePoint)56 AudioHalVolumeCurve::CurvePoint AudioPolicyConfigXmlConverter::convertCurvePointToAidl(
57 const std::string& xsdcCurvePoint) {
58 AudioHalVolumeCurve::CurvePoint aidlCurvePoint{};
59 if (sscanf(xsdcCurvePoint.c_str(), "%" SCNd8 ",%d", &aidlCurvePoint.index,
60 &aidlCurvePoint.attenuationMb) != 2) {
61 aidlCurvePoint.index = kInvalidCurvePointIndex;
62 }
63 return aidlCurvePoint;
64 }
65
convertVolumeCurveToAidl(const xsd::Volume & xsdcVolumeCurve)66 AudioHalVolumeCurve AudioPolicyConfigXmlConverter::convertVolumeCurveToAidl(
67 const xsd::Volume& xsdcVolumeCurve) {
68 AudioHalVolumeCurve aidlVolumeCurve;
69 aidlVolumeCurve.deviceCategory =
70 static_cast<AudioHalVolumeCurve::DeviceCategory>(xsdcVolumeCurve.getDeviceCategory());
71 if (xsdcVolumeCurve.hasRef()) {
72 if (mVolumesReferenceMap.empty()) {
73 mVolumesReferenceMap = generateReferenceMap<xsd::Volumes, xsd::Reference>(
74 getXsdcConfig()->getVolumes());
75 }
76 aidlVolumeCurve.curvePoints =
77 convertCollectionToAidlUnchecked<std::string, AudioHalVolumeCurve::CurvePoint>(
78 mVolumesReferenceMap.at(xsdcVolumeCurve.getRef()).getPoint(),
79 std::bind(&AudioPolicyConfigXmlConverter::convertCurvePointToAidl, this,
80 std::placeholders::_1));
81 } else {
82 aidlVolumeCurve.curvePoints =
83 convertCollectionToAidlUnchecked<std::string, AudioHalVolumeCurve::CurvePoint>(
84 xsdcVolumeCurve.getPoint(),
85 std::bind(&AudioPolicyConfigXmlConverter::convertCurvePointToAidl, this,
86 std::placeholders::_1));
87 }
88 return aidlVolumeCurve;
89 }
90
mapStreamToVolumeCurve(const xsd::Volume & xsdcVolumeCurve)91 void AudioPolicyConfigXmlConverter::mapStreamToVolumeCurve(const xsd::Volume& xsdcVolumeCurve) {
92 mStreamToVolumeCurvesMap[xsdcVolumeCurve.getStream()].push_back(
93 convertVolumeCurveToAidl(xsdcVolumeCurve));
94 }
95
getSurroundSoundConfig()96 const SurroundSoundConfig& AudioPolicyConfigXmlConverter::getSurroundSoundConfig() {
97 static const SurroundSoundConfig aidlSurroundSoundConfig = [this]() {
98 if (auto xsdcConfig = getXsdcConfig(); xsdcConfig && xsdcConfig->hasSurroundSound()) {
99 auto configConv = xsdc2aidl_SurroundSoundConfig(*xsdcConfig->getFirstSurroundSound());
100 if (configConv.ok()) {
101 return configConv.value();
102 }
103 LOG(ERROR) << "There was an error converting surround formats to AIDL: "
104 << configConv.error();
105 }
106 LOG(WARNING) << "Audio policy config does not have <surroundSound> section, using default";
107 return getDefaultSurroundSoundConfig();
108 }();
109 return aidlSurroundSoundConfig;
110 }
111
getAidlEngineConfig()112 const AudioHalEngineConfig& AudioPolicyConfigXmlConverter::getAidlEngineConfig() {
113 if (mAidlEngineConfig.volumeGroups.empty() && getXsdcConfig() &&
114 getXsdcConfig()->hasVolumes()) {
115 parseVolumes();
116 }
117 return mAidlEngineConfig;
118 }
119
120 // static
getDefaultSurroundSoundConfig()121 const SurroundSoundConfig& AudioPolicyConfigXmlConverter::getDefaultSurroundSoundConfig() {
122 // Provide a config similar to the one used by the framework by default
123 // (see AudioPolicyConfig::setDefaultSurroundFormats).
124 #define ENCODED_FORMAT(format) \
125 AudioFormatDescription { \
126 .encoding = ::android::format \
127 }
128 #define SIMPLE_FORMAT(format) \
129 SurroundSoundConfig::SurroundFormatFamily { \
130 .primaryFormat = ENCODED_FORMAT(format) \
131 }
132
133 static const SurroundSoundConfig defaultConfig = {
134 .formatFamilies = {
135 SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_AC3),
136 SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_EAC3),
137 SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS),
138 SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS_HD),
139 SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS_HD_MA),
140 SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS_UHD_P1),
141 SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS_UHD_P2),
142 SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DOLBY_TRUEHD),
143 SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_EAC3_JOC),
144 SurroundSoundConfig::SurroundFormatFamily{
145 .primaryFormat = ENCODED_FORMAT(MEDIA_MIMETYPE_AUDIO_AAC_LC),
146 .subFormats =
147 {
148 ENCODED_FORMAT(MEDIA_MIMETYPE_AUDIO_AAC_HE_V1),
149 ENCODED_FORMAT(MEDIA_MIMETYPE_AUDIO_AAC_HE_V2),
150 ENCODED_FORMAT(MEDIA_MIMETYPE_AUDIO_AAC_ELD),
151 ENCODED_FORMAT(MEDIA_MIMETYPE_AUDIO_AAC_XHE),
152 }},
153 SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_AC4),
154 }};
155 #undef SIMPLE_FORMAT
156 #undef ENCODED_FORMAT
157
158 return defaultConfig;
159 }
160
mapStreamsToVolumeCurves()161 void AudioPolicyConfigXmlConverter::mapStreamsToVolumeCurves() {
162 if (getXsdcConfig()->hasVolumes()) {
163 for (const xsd::Volumes& xsdcWrapperType : getXsdcConfig()->getVolumes()) {
164 for (const xsd::Volume& xsdcVolume : xsdcWrapperType.getVolume()) {
165 mapStreamToVolumeCurve(xsdcVolume);
166 }
167 }
168 }
169 }
170
addVolumeGroupstoEngineConfig()171 void AudioPolicyConfigXmlConverter::addVolumeGroupstoEngineConfig() {
172 for (const auto& [xsdcStream, volumeCurves] : mStreamToVolumeCurvesMap) {
173 AudioHalVolumeGroup volumeGroup;
174 volumeGroup.name = xsd::toString(xsdcStream);
175 if (static_cast<int>(xsdcStream) >= AUDIO_STREAM_PUBLIC_CNT) {
176 volumeGroup.minIndex = kDefaultVolumeIndexMin;
177 volumeGroup.maxIndex = kDefaultVolumeIndexMax;
178 } else {
179 volumeGroup.minIndex = KVolumeIndexDeferredToAudioService;
180 volumeGroup.maxIndex = KVolumeIndexDeferredToAudioService;
181 }
182 volumeGroup.volumeCurves = volumeCurves;
183 mAidlEngineConfig.volumeGroups.push_back(std::move(volumeGroup));
184 }
185 }
186
parseVolumes()187 void AudioPolicyConfigXmlConverter::parseVolumes() {
188 if (mStreamToVolumeCurvesMap.empty() && getXsdcConfig()->hasVolumes()) {
189 mapStreamsToVolumeCurves();
190 addVolumeGroupstoEngineConfig();
191 }
192 }
193 } // namespace aidl::android::hardware::audio::core::internal
194