xref: /aosp_15_r20/frameworks/av/services/audiopolicy/common/managerdefinitions/src/IOProfile.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::IOProfile"
18 //#define LOG_NDEBUG 0
19 
20 #include <system/audio.h>
21 #include "IOProfile.h"
22 #include "HwModule.h"
23 #include "TypeConverter.h"
24 
25 namespace android {
26 
IOProfile(const std::string & name,audio_port_role_t role)27 IOProfile::IOProfile(const std::string &name, audio_port_role_t role)
28         : AudioPort(name, AUDIO_PORT_TYPE_MIX, role),
29           curOpenCount(0),
30           curActiveCount(0) {
31     if (role == AUDIO_PORT_ROLE_SOURCE) {
32         mMixerBehaviors.insert(AUDIO_MIXER_BEHAVIOR_DEFAULT);
33     }
34 }
35 
getCompatibilityScore(const android::DeviceVector & devices,uint32_t samplingRate,uint32_t * updatedSamplingRate,audio_format_t format,audio_format_t * updatedFormat,audio_channel_mask_t channelMask,audio_channel_mask_t * updatedChannelMask,uint32_t flags) const36 IOProfile::CompatibilityScore IOProfile::getCompatibilityScore(
37         const android::DeviceVector &devices,
38         uint32_t samplingRate,
39         uint32_t *updatedSamplingRate,
40         audio_format_t format,
41         audio_format_t *updatedFormat,
42         audio_channel_mask_t channelMask,
43         audio_channel_mask_t *updatedChannelMask,
44         // FIXME type punning here
45         uint32_t flags) const {
46     const bool isPlaybackThread =
47             getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SOURCE;
48     const bool isRecordThread =
49             getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SINK;
50     ALOG_ASSERT(isPlaybackThread != isRecordThread);
51     const auto flagsCompatibleScore = getFlagsCompatibleScore(flags);
52     if (!areAllDevicesSupported(devices) || flagsCompatibleScore == NO_MATCH) {
53         return NO_MATCH;
54     }
55 
56     if (!audio_is_valid_format(format) ||
57             (isPlaybackThread && (samplingRate == 0 || !audio_is_output_channel(channelMask))) ||
58             (isRecordThread && (!audio_is_input_channel(channelMask)))) {
59          return NO_MATCH;
60     }
61 
62     audio_format_t myUpdatedFormat = format;
63     audio_channel_mask_t myUpdatedChannelMask = channelMask;
64     uint32_t myUpdatedSamplingRate = samplingRate;
65     const struct audio_port_config config = {
66         .config_mask = AUDIO_PORT_CONFIG_ALL & ~AUDIO_PORT_CONFIG_GAIN,
67         .sample_rate = samplingRate,
68         .channel_mask = channelMask,
69         .format = format,
70     };
71     auto result = NO_MATCH;
72     if (isRecordThread)
73     {
74         if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
75             if (checkIdenticalAudioProfile(&config) != NO_ERROR) {
76                 return result;
77             }
78             result = EXACT_MATCH;
79         } else if (checkExactAudioProfile(&config) == NO_ERROR) {
80             result = EXACT_MATCH;
81         } else if (checkCompatibleAudioProfile(
82                 myUpdatedSamplingRate, myUpdatedChannelMask, myUpdatedFormat) == NO_ERROR) {
83             if (flagsCompatibleScore == EXACT_MATCH) {
84                 result = PARTIAL_MATCH_WITH_FLAG;
85             } else {
86                 result = PARTIAL_MATCH;
87             }
88         } else {
89             return result;
90         }
91     } else {
92         if ((flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) != 0 ||
93             (flags & AUDIO_OUTPUT_FLAG_BIT_PERFECT) != 0) {
94             if (checkIdenticalAudioProfile(&config) != NO_ERROR) {
95                 return result;
96             }
97             result = EXACT_MATCH;
98         } else if (checkExactAudioProfile(&config) == NO_ERROR) {
99             result = EXACT_MATCH;
100         } else {
101             return result;
102         }
103     }
104 
105     if (updatedSamplingRate != nullptr) {
106         *updatedSamplingRate = myUpdatedSamplingRate;
107     }
108     if (updatedFormat != nullptr) {
109         *updatedFormat = myUpdatedFormat;
110     }
111     if (updatedChannelMask != nullptr) {
112         *updatedChannelMask = myUpdatedChannelMask;
113     }
114     return result;
115 }
116 
areAllDevicesSupported(const DeviceVector & devices) const117 bool IOProfile::areAllDevicesSupported(const DeviceVector &devices) const {
118     if (devices.empty()) {
119         return true;
120     }
121     return mSupportedDevices.containsAllDevices(devices);
122 }
123 
isCompatibleProfileForFlags(uint32_t flags) const124 bool IOProfile::isCompatibleProfileForFlags(uint32_t flags) const {
125     return getFlagsCompatibleScore(flags) != NO_MATCH;
126 }
127 
containsSingleDeviceSupportingEncodedFormats(const sp<DeviceDescriptor> & device) const128 bool IOProfile::containsSingleDeviceSupportingEncodedFormats(
129         const sp<DeviceDescriptor>& device) const {
130     if (device == nullptr) {
131         return false;
132     }
133     DeviceVector deviceList = mSupportedDevices.getDevicesFromType(device->type());
134     return std::count_if(deviceList.begin(), deviceList.end(),
135             [&device](sp<DeviceDescriptor> deviceDesc) {
136                 return device == deviceDesc && deviceDesc->hasCurrentEncodedFormat(); }) == 1;
137 }
138 
toSupportedMixerAttributes(std::vector<audio_mixer_attributes_t> * mixerAttributes) const139 void IOProfile::toSupportedMixerAttributes(
140         std::vector<audio_mixer_attributes_t> *mixerAttributes) const {
141     if (!hasDynamicAudioProfile()) {
142         // The mixer attributes is only supported when there is a dynamic profile.
143         return;
144     }
145     for (const auto& profile : mProfiles) {
146         if (!profile->isValid()) {
147             continue;
148         }
149         for (const auto sampleRate : profile->getSampleRates()) {
150             for (const auto channelMask : profile->getChannels()) {
151                 const audio_config_base_t config = {
152                         .sample_rate = sampleRate,
153                         .channel_mask = channelMask,
154                         .format = profile->getFormat(),
155                 };
156                 for (const auto mixerBehavior : mMixerBehaviors) {
157                     mixerAttributes->push_back({
158                         .config = config,
159                         .mixer_behavior = mixerBehavior
160                     });
161                 }
162             }
163         }
164     }
165 }
166 
refreshMixerBehaviors()167 void IOProfile::refreshMixerBehaviors() {
168     if (getRole() == AUDIO_PORT_ROLE_SOURCE) {
169         mMixerBehaviors.clear();
170         mMixerBehaviors.insert(AUDIO_MIXER_BEHAVIOR_DEFAULT);
171         if (mFlags.output & AUDIO_OUTPUT_FLAG_BIT_PERFECT) {
172             mMixerBehaviors.insert(AUDIO_MIXER_BEHAVIOR_BIT_PERFECT);
173         }
174     }
175 }
176 
readFromParcelable(const media::AudioPortFw & parcelable)177 status_t IOProfile::readFromParcelable(const media::AudioPortFw &parcelable) {
178     status_t status = AudioPort::readFromParcelable(parcelable);
179     if (status == OK) {
180         refreshMixerBehaviors();
181     }
182     return status;
183 }
184 
importAudioPort(const audio_port_v7 & port)185 void IOProfile::importAudioPort(const audio_port_v7 &port) {
186     if (mProfiles.hasDynamicFormat()) {
187         std::set<audio_format_t> formats;
188         for (size_t i = 0; i < port.num_audio_profiles; ++i) {
189             formats.insert(port.audio_profiles[i].format);
190         }
191         addProfilesForFormats(mProfiles, FormatVector(formats.begin(), formats.end()));
192     }
193     for (audio_format_t format : mProfiles.getSupportedFormats()) {
194         for (size_t i = 0; i < port.num_audio_profiles; ++i) {
195             if (port.audio_profiles[i].format == format) {
196                 ChannelMaskSet channelMasks(port.audio_profiles[i].channel_masks,
197                         port.audio_profiles[i].channel_masks +
198                                 port.audio_profiles[i].num_channel_masks);
199                 SampleRateSet sampleRates(port.audio_profiles[i].sample_rates,
200                         port.audio_profiles[i].sample_rates +
201                                 port.audio_profiles[i].num_sample_rates);
202                 addDynamicAudioProfileAndSort(
203                         mProfiles, sp<AudioProfile>::make(
204                                 format, channelMasks, sampleRates));
205             }
206         }
207     }
208 }
209 
getFlagsCompatibleScore(uint32_t flags) const210 IOProfile::CompatibilityScore IOProfile::getFlagsCompatibleScore(uint32_t flags) const {
211     const bool isPlaybackThread =
212             getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SOURCE;
213     const bool isRecordThread =
214             getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SINK;
215     ALOG_ASSERT(isPlaybackThread != isRecordThread);
216 
217     const uint32_t mustMatchOutputFlags =
218             AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_HW_AV_SYNC|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
219     if (isPlaybackThread &&
220         !audio_output_flags_is_subset((audio_output_flags_t)getFlags(),
221                                       (audio_output_flags_t)flags,
222                                       mustMatchOutputFlags)) {
223         return NO_MATCH;
224     }
225     // The only input flag that is allowed to be different is the fast flag.
226     // An existing fast stream is compatible with a normal track request.
227     // An existing normal stream is compatible with a fast track request,
228     // but the fast request will be denied by AudioFlinger and converted to normal track.
229     if (isRecordThread) {
230         const auto unmatchedFlag = getFlags() ^ flags;
231         if (unmatchedFlag == AUDIO_INPUT_FLAG_NONE) {
232             return EXACT_MATCH;
233         } else if (unmatchedFlag == AUDIO_INPUT_FLAG_FAST) {
234             return PARTIAL_MATCH;
235         } else {
236             return NO_MATCH;
237         }
238     }
239 
240     return EXACT_MATCH;
241 }
242 
dump(String8 * dst,int spaces) const243 void IOProfile::dump(String8 *dst, int spaces) const
244 {
245     String8 extraInfo;
246     extraInfo.appendFormat("0x%04x", getFlags());
247     std::string flagsLiteral =
248             getRole() == AUDIO_PORT_ROLE_SINK ?
249             toString(static_cast<audio_input_flags_t>(getFlags())) :
250             getRole() == AUDIO_PORT_ROLE_SOURCE ?
251             toString(static_cast<audio_output_flags_t>(getFlags())) : "";
252     if (!flagsLiteral.empty()) {
253         extraInfo.appendFormat(" (%s)", flagsLiteral.c_str());
254     }
255 
256     std::string portStr;
257     AudioPort::dump(&portStr, spaces, extraInfo.c_str());
258     dst->append(portStr.c_str());
259 
260     mSupportedDevices.dump(dst, String8("- Supported"), spaces - 2, false);
261     dst->appendFormat("%*s- maxOpenCount: %u; curOpenCount: %u\n",
262             spaces - 2, "", maxOpenCount, curOpenCount);
263     dst->appendFormat("%*s- maxActiveCount: %u; curActiveCount: %u\n",
264             spaces - 2, "", maxActiveCount, curActiveCount);
265     dst->appendFormat("%*s- recommendedMuteDurationMs: %u ms\n",
266             spaces - 2, "", recommendedMuteDurationMs);
267     if (hasDynamicAudioProfile() && !mMixerBehaviors.empty()) {
268         dst->appendFormat("%*s- mixerBehaviors: %s\n",
269                 spaces - 2, "", dumpMixerBehaviors(mMixerBehaviors).c_str());
270     }
271 }
272 
log()273 void IOProfile::log()
274 {
275     // @TODO: forward log to AudioPort
276 }
277 
278 } // namespace android
279