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