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