1 /*
2 * Copyright (C) 2015 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 #define LOG_TAG "APM::PolicyAudioPort"
18 //#define LOG_NDEBUG 0
19 #include "TypeConverter.h"
20 #include "PolicyAudioPort.h"
21 #include "HwModule.h"
22 #include <policy.h>
23
24 #ifndef ARRAY_SIZE
25 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
26 #endif
27
28 namespace android {
29
30 // --- PolicyAudioPort class implementation
attach(const sp<HwModule> & module)31 void PolicyAudioPort::attach(const sp<HwModule>& module)
32 {
33 ALOGV("%s: attaching module %s to port %s",
34 __FUNCTION__, getModuleName(), asAudioPort()->getName().c_str());
35 mModule = module;
36 }
37
detach()38 void PolicyAudioPort::detach()
39 {
40 mModule = nullptr;
41 }
42
43 // Note that is a different namespace than AudioFlinger unique IDs
getNextUniqueId()44 audio_port_handle_t PolicyAudioPort::getNextUniqueId()
45 {
46 return getNextHandle();
47 }
48
getModuleHandle() const49 audio_module_handle_t PolicyAudioPort::getModuleHandle() const
50 {
51 return mModule != 0 ? mModule->getHandle() : AUDIO_MODULE_HANDLE_NONE;
52 }
53
getModuleVersionMajor() const54 uint32_t PolicyAudioPort::getModuleVersionMajor() const
55 {
56 return mModule != 0 ? mModule->getHalVersionMajor() : 0;
57 }
58
getModuleName() const59 const char *PolicyAudioPort::getModuleName() const
60 {
61 return mModule != 0 ? mModule->getName() : "invalid module";
62 }
63
checkExactAudioProfile(const struct audio_port_config * config) const64 status_t PolicyAudioPort::checkExactAudioProfile(const struct audio_port_config *config) const
65 {
66 status_t status = NO_ERROR;
67 auto config_mask = config->config_mask;
68 if (config_mask & AUDIO_PORT_CONFIG_GAIN) {
69 config_mask &= ~AUDIO_PORT_CONFIG_GAIN;
70 status = asAudioPort()->checkGain(&config->gain, config->gain.index);
71 if (status != NO_ERROR) {
72 return status;
73 }
74 }
75 if (config_mask != 0) {
76 // TODO should we check sample_rate / channel_mask / format separately?
77 status = checkExactProfile(asAudioPort()->getAudioProfiles(), config->sample_rate,
78 config->channel_mask, config->format);
79 }
80 return status;
81 }
82
pickSamplingRate(uint32_t & pickedRate,const SampleRateSet & samplingRates) const83 void PolicyAudioPort::pickSamplingRate(uint32_t &pickedRate,
84 const SampleRateSet &samplingRates) const
85 {
86 pickedRate = 0;
87 // For direct outputs, pick minimum sampling rate: this helps ensuring that the
88 // channel count / sampling rate combination chosen will be supported by the connected
89 // sink
90 if (isDirectOutput()) {
91 uint32_t samplingRate = UINT_MAX;
92 for (const auto rate : samplingRates) {
93 if ((rate < samplingRate) && (rate > 0)) {
94 samplingRate = rate;
95 }
96 }
97 pickedRate = (samplingRate == UINT_MAX) ? 0 : samplingRate;
98 } else {
99 uint32_t maxRate = SAMPLE_RATE_HZ_MAX;
100
101 // For mixed output and inputs, use max mixer sampling rates. Do not
102 // limit sampling rate otherwise
103 // For inputs, also see checkCompatibleSamplingRate().
104 if (asAudioPort()->getType() == AUDIO_PORT_TYPE_MIX) {
105 maxRate = UINT_MAX;
106 }
107 // TODO: should mSamplingRates[] be ordered in terms of our preference
108 // and we return the first (and hence most preferred) match? This is of concern if
109 // we want to choose 96kHz over 192kHz for USB driver stability or resource constraints.
110 for (const auto rate : samplingRates) {
111 if ((rate > pickedRate) && (rate <= maxRate)) {
112 pickedRate = rate;
113 }
114 }
115 }
116 }
117
pickChannelMask(audio_channel_mask_t & pickedChannelMask,const ChannelMaskSet & channelMasks) const118 void PolicyAudioPort::pickChannelMask(audio_channel_mask_t &pickedChannelMask,
119 const ChannelMaskSet &channelMasks) const
120 {
121 pickedChannelMask = AUDIO_CHANNEL_NONE;
122 // For direct outputs, pick minimum channel count: this helps ensuring that the
123 // channel count / sampling rate combination chosen will be supported by the connected
124 // sink
125 if (isDirectOutput()) {
126 uint32_t channelCount = UINT_MAX;
127 for (const auto channelMask : channelMasks) {
128 uint32_t cnlCount;
129 if (asAudioPort()->useInputChannelMask()) {
130 cnlCount = audio_channel_count_from_in_mask(channelMask);
131 } else {
132 cnlCount = audio_channel_count_from_out_mask(channelMask);
133 }
134 if ((cnlCount < channelCount) && (cnlCount > 0)) {
135 pickedChannelMask = channelMask;
136 channelCount = cnlCount;
137 }
138 }
139 } else {
140 uint32_t channelCount = 0;
141 uint32_t maxCount = MAX_MIXER_CHANNEL_COUNT;
142
143 // For mixed output and inputs, use max mixer channel count. Do not
144 // limit channel count otherwise
145 if (asAudioPort()->getType() != AUDIO_PORT_TYPE_MIX) {
146 maxCount = UINT_MAX;
147 }
148 for (const auto channelMask : channelMasks) {
149 uint32_t cnlCount;
150 if (asAudioPort()->useInputChannelMask()) {
151 cnlCount = audio_channel_count_from_in_mask(channelMask);
152 } else {
153 cnlCount = audio_channel_count_from_out_mask(channelMask);
154 }
155 if ((cnlCount > channelCount) && (cnlCount <= maxCount)) {
156 pickedChannelMask = channelMask;
157 channelCount = cnlCount;
158 }
159 }
160 }
161 }
162
163 /* format in order of increasing preference */
164 const audio_format_t PolicyAudioPort::sPcmFormatCompareTable[] = {
165 AUDIO_FORMAT_DEFAULT,
166 AUDIO_FORMAT_PCM_16_BIT,
167 AUDIO_FORMAT_PCM_8_24_BIT,
168 AUDIO_FORMAT_PCM_24_BIT_PACKED,
169 AUDIO_FORMAT_PCM_32_BIT,
170 AUDIO_FORMAT_PCM_FLOAT,
171 };
172
compareFormats(audio_format_t format1,audio_format_t format2)173 int PolicyAudioPort::compareFormats(audio_format_t format1, audio_format_t format2)
174 {
175 // NOTE: AUDIO_FORMAT_INVALID is also considered not PCM and will be compared equal to any
176 // compressed format and better than any PCM format. This is by design of pickFormat()
177 if (!audio_is_linear_pcm(format1)) {
178 if (!audio_is_linear_pcm(format2)) {
179 return 0;
180 }
181 return 1;
182 }
183 if (!audio_is_linear_pcm(format2)) {
184 return -1;
185 }
186
187 int index1 = -1, index2 = -1;
188 for (size_t i = 0;
189 (i < ARRAY_SIZE(sPcmFormatCompareTable)) && ((index1 == -1) || (index2 == -1));
190 i ++) {
191 if (sPcmFormatCompareTable[i] == format1) {
192 index1 = i;
193 }
194 if (sPcmFormatCompareTable[i] == format2) {
195 index2 = i;
196 }
197 }
198 // format1 not found => index1 < 0 => format2 > format1
199 // format2 not found => index2 < 0 => format2 < format1
200 return index1 - index2;
201 }
202
formatDistance(audio_format_t format1,audio_format_t format2)203 uint32_t PolicyAudioPort::formatDistance(audio_format_t format1, audio_format_t format2)
204 {
205 if (format1 == format2) {
206 return 0;
207 }
208 if (format1 == AUDIO_FORMAT_INVALID || format2 == AUDIO_FORMAT_INVALID) {
209 return kFormatDistanceMax;
210 }
211 int diffBytes = (int)audio_bytes_per_sample(format1) -
212 audio_bytes_per_sample(format2);
213
214 return abs(diffBytes);
215 }
216
isBetterFormatMatch(audio_format_t newFormat,audio_format_t currentFormat,audio_format_t targetFormat)217 bool PolicyAudioPort::isBetterFormatMatch(audio_format_t newFormat,
218 audio_format_t currentFormat,
219 audio_format_t targetFormat)
220 {
221 return formatDistance(newFormat, targetFormat) < formatDistance(currentFormat, targetFormat);
222 }
223
pickAudioProfile(uint32_t & samplingRate,audio_channel_mask_t & channelMask,audio_format_t & format) const224 void PolicyAudioPort::pickAudioProfile(uint32_t &samplingRate,
225 audio_channel_mask_t &channelMask,
226 audio_format_t &format) const
227 {
228 format = AUDIO_FORMAT_DEFAULT;
229 samplingRate = 0;
230 channelMask = AUDIO_CHANNEL_NONE;
231
232 // special case for uninitialized dynamic profile
233 if (!asAudioPort()->hasValidAudioProfile()) {
234 return;
235 }
236 audio_format_t bestFormat = sPcmFormatCompareTable[ARRAY_SIZE(sPcmFormatCompareTable) - 1];
237 // For mixed output and inputs, use best mixer output format.
238 // Do not limit format otherwise
239 if ((asAudioPort()->getType() != AUDIO_PORT_TYPE_MIX) || isDirectOutput()) {
240 bestFormat = AUDIO_FORMAT_INVALID;
241 }
242
243 const AudioProfileVector& audioProfiles = asAudioPort()->getAudioProfiles();
244 for (size_t i = 0; i < audioProfiles.size(); i ++) {
245 if (!audioProfiles[i]->isValid()) {
246 continue;
247 }
248 audio_format_t formatToCompare = audioProfiles[i]->getFormat();
249 if ((compareFormats(formatToCompare, format) > 0) &&
250 (compareFormats(formatToCompare, bestFormat) <= 0)) {
251 uint32_t pickedSamplingRate = 0;
252 audio_channel_mask_t pickedChannelMask = AUDIO_CHANNEL_NONE;
253 pickChannelMask(pickedChannelMask, audioProfiles[i]->getChannels());
254 pickSamplingRate(pickedSamplingRate, audioProfiles[i]->getSampleRates());
255
256 if (formatToCompare != AUDIO_FORMAT_DEFAULT && pickedChannelMask != AUDIO_CHANNEL_NONE
257 && pickedSamplingRate != 0) {
258 format = formatToCompare;
259 channelMask = pickedChannelMask;
260 samplingRate = pickedSamplingRate;
261 // TODO: shall we return on the first one or still trying to pick a better Profile?
262 }
263 }
264 }
265 ALOGV("%s Port[nm:%s] profile rate=%d, format=%d, channels=%d", __FUNCTION__,
266 asAudioPort()->getName().c_str(), samplingRate, channelMask, format);
267 }
268
269 // --- PolicyAudioPortConfig class implementation
270
validationBeforeApplyConfig(const struct audio_port_config * config) const271 status_t PolicyAudioPortConfig::validationBeforeApplyConfig(
272 const struct audio_port_config *config) const
273 {
274 sp<PolicyAudioPort> policyAudioPort = getPolicyAudioPort();
275 return policyAudioPort ? policyAudioPort->checkExactAudioProfile(config) : NO_INIT;
276 }
277
toPolicyAudioPortConfig(struct audio_port_config * dstConfig,const struct audio_port_config * srcConfig) const278 void PolicyAudioPortConfig::toPolicyAudioPortConfig(struct audio_port_config *dstConfig,
279 const struct audio_port_config *srcConfig) const
280 {
281 if (dstConfig->config_mask & AUDIO_PORT_CONFIG_FLAGS) {
282 if ((srcConfig != nullptr) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_FLAGS)) {
283 dstConfig->flags = srcConfig->flags;
284 } else {
285 dstConfig->flags = mFlags;
286 }
287 } else {
288 dstConfig->flags = { AUDIO_INPUT_FLAG_NONE };
289 }
290 }
291
292
293
294 } // namespace android
295