• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <algorithm>
18 #include <chrono>
19 
20 #define LOG_TAG "VtsHalAudio.ModuleConfig"
21 #include <android-base/logging.h>
22 
23 #include <Utils.h>
24 #include <aidl/android/media/audio/common/AudioInputFlags.h>
25 #include <aidl/android/media/audio/common/AudioIoFlags.h>
26 #include <aidl/android/media/audio/common/AudioOutputFlags.h>
27 #include <error/expected_utils.h>
28 
29 #include "ModuleConfig.h"
30 
31 using namespace android;
32 using namespace std::chrono_literals;
33 
34 using aidl::android::hardware::audio::common::isBitPositionFlagSet;
35 using aidl::android::hardware::audio::core::IModule;
36 using aidl::android::media::audio::common::AudioChannelLayout;
37 using aidl::android::media::audio::common::AudioDeviceDescription;
38 using aidl::android::media::audio::common::AudioDeviceType;
39 using aidl::android::media::audio::common::AudioFormatDescription;
40 using aidl::android::media::audio::common::AudioFormatType;
41 using aidl::android::media::audio::common::AudioInputFlags;
42 using aidl::android::media::audio::common::AudioIoFlags;
43 using aidl::android::media::audio::common::AudioOutputFlags;
44 using aidl::android::media::audio::common::AudioPort;
45 using aidl::android::media::audio::common::AudioPortConfig;
46 using aidl::android::media::audio::common::AudioPortExt;
47 using aidl::android::media::audio::common::AudioProfile;
48 using aidl::android::media::audio::common::AudioUsage;
49 using aidl::android::media::audio::common::Int;
50 
51 // static
52 std::vector<aidl::android::media::audio::common::AudioPort>
getAudioPortsForDeviceTypes(const std::vector<aidl::android::media::audio::common::AudioPort> & ports,const std::vector<AudioDeviceType> & deviceTypes,const std::string & connection)53 ModuleConfig::getAudioPortsForDeviceTypes(
54         const std::vector<aidl::android::media::audio::common::AudioPort>& ports,
55         const std::vector<AudioDeviceType>& deviceTypes, const std::string& connection) {
56     std::vector<AudioPort> result;
57     for (const auto& port : ports) {
58         if (port.ext.getTag() != AudioPortExt::Tag::device) continue;
59         const auto type = port.ext.get<AudioPortExt::Tag::device>().device.type;
60         if (type.connection == connection) {
61             for (auto deviceType : deviceTypes) {
62                 if (type.type == deviceType) {
63                     result.push_back(port);
64                 }
65             }
66         }
67     }
68     return result;
69 }
70 
71 // static
getBuiltInMicPorts(const std::vector<aidl::android::media::audio::common::AudioPort> & ports)72 std::vector<aidl::android::media::audio::common::AudioPort> ModuleConfig::getBuiltInMicPorts(
73         const std::vector<aidl::android::media::audio::common::AudioPort>& ports) {
74     return getAudioPortsForDeviceTypes(
75             ports, std::vector<AudioDeviceType>{AudioDeviceType::IN_MICROPHONE,
76                                                 AudioDeviceType::IN_MICROPHONE_BACK});
77 }
78 
79 template <typename T>
findById(const std::vector<T> & v,int32_t id)80 auto findById(const std::vector<T>& v, int32_t id) {
81     return std::find_if(v.begin(), v.end(), [&](const auto& p) { return p.id == id; });
82 }
83 
ModuleConfig(IModule * module)84 ModuleConfig::ModuleConfig(IModule* module) {
85     mStatus = module->getAudioPorts(&mPorts);
86     if (!mStatus.isOk()) return;
87     for (const auto& port : mPorts) {
88         if (port.ext.getTag() != AudioPortExt::Tag::device) continue;
89         const auto& devicePort = port.ext.get<AudioPortExt::Tag::device>();
90         if (devicePort.device.type.connection.empty()) {
91             const bool isInput = port.flags.getTag() == AudioIoFlags::Tag::input;
92             // Permanently attached device.
93             if (isInput) {
94                 mAttachedSourceDevicePorts.insert(port.id);
95             } else {
96                 mAttachedSinkDevicePorts.insert(port.id);
97             }
98         } else {
99             mExternalDevicePorts.insert(port.id);
100         }
101     }
102     if (!mStatus.isOk()) return;
103     mStatus = module->getAudioRoutes(&mRoutes);
104     if (!mStatus.isOk()) return;
105     mStatus = module->getAudioPortConfigs(&mInitialConfigs);
106 }
107 
getAttachedDevicePorts() const108 std::vector<AudioPort> ModuleConfig::getAttachedDevicePorts() const {
109     std::vector<AudioPort> result;
110     std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
111         return mAttachedSinkDevicePorts.count(port.id) != 0 ||
112                mAttachedSourceDevicePorts.count(port.id) != 0;
113     });
114     return result;
115 }
116 
117 std::vector<aidl::android::media::audio::common::AudioPort>
getAudioPortsForDeviceTypes(const std::vector<AudioDeviceType> & deviceTypes,const std::string & connection) const118 ModuleConfig::getAudioPortsForDeviceTypes(const std::vector<AudioDeviceType>& deviceTypes,
119                                           const std::string& connection) const {
120     return getAudioPortsForDeviceTypes(mPorts, deviceTypes, connection);
121 }
122 
getConnectedExternalDevicePorts() const123 std::vector<AudioPort> ModuleConfig::getConnectedExternalDevicePorts() const {
124     std::vector<AudioPort> result;
125     std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
126         return mConnectedExternalSinkDevicePorts.count(port.id) != 0 ||
127                mConnectedExternalSourceDevicePorts.count(port.id) != 0;
128     });
129     return result;
130 }
131 
getConnectedSinkDevicePorts() const132 std::set<int32_t> ModuleConfig::getConnectedSinkDevicePorts() const {
133     std::set<int32_t> result;
134     result.insert(mAttachedSinkDevicePorts.begin(), mAttachedSinkDevicePorts.end());
135     result.insert(mConnectedExternalSinkDevicePorts.begin(),
136                   mConnectedExternalSinkDevicePorts.end());
137     return result;
138 }
139 
getConnectedSourceDevicePorts() const140 std::set<int32_t> ModuleConfig::getConnectedSourceDevicePorts() const {
141     std::set<int32_t> result;
142     result.insert(mAttachedSourceDevicePorts.begin(), mAttachedSourceDevicePorts.end());
143     result.insert(mConnectedExternalSourceDevicePorts.begin(),
144                   mConnectedExternalSourceDevicePorts.end());
145     return result;
146 }
147 
getExternalDevicePorts() const148 std::vector<AudioPort> ModuleConfig::getExternalDevicePorts() const {
149     std::vector<AudioPort> result;
150     std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result),
151                  [&](const auto& port) { return mExternalDevicePorts.count(port.id) != 0; });
152     return result;
153 }
154 
getInputMixPorts(bool connectedOnly) const155 std::vector<AudioPort> ModuleConfig::getInputMixPorts(bool connectedOnly) const {
156     std::vector<AudioPort> result;
157     std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
158         return port.ext.getTag() == AudioPortExt::Tag::mix &&
159                port.flags.getTag() == AudioIoFlags::Tag::input &&
160                (!connectedOnly || !getConnectedSourceDevicesPortsForMixPort(port).empty());
161     });
162     return result;
163 }
164 
getOutputMixPorts(bool connectedOnly) const165 std::vector<AudioPort> ModuleConfig::getOutputMixPorts(bool connectedOnly) const {
166     std::vector<AudioPort> result;
167     std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
168         return port.ext.getTag() == AudioPortExt::Tag::mix &&
169                port.flags.getTag() == AudioIoFlags::Tag::output &&
170                (!connectedOnly || !getConnectedSinkDevicesPortsForMixPort(port).empty());
171     });
172     return result;
173 }
174 
getNonBlockingMixPorts(bool connectedOnly,bool singlePort) const175 std::vector<AudioPort> ModuleConfig::getNonBlockingMixPorts(bool connectedOnly,
176                                                             bool singlePort) const {
177     return findMixPorts(false /*isInput*/, connectedOnly, singlePort, [&](const AudioPort& port) {
178         return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
179                                     AudioOutputFlags::NON_BLOCKING);
180     });
181 }
182 
getOffloadMixPorts(bool connectedOnly,bool singlePort) const183 std::vector<AudioPort> ModuleConfig::getOffloadMixPorts(bool connectedOnly, bool singlePort) const {
184     return findMixPorts(false /*isInput*/, connectedOnly, singlePort, [&](const AudioPort& port) {
185         return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
186                                     AudioOutputFlags::COMPRESS_OFFLOAD);
187     });
188 }
189 
getPrimaryMixPorts(bool connectedOnly,bool singlePort) const190 std::vector<AudioPort> ModuleConfig::getPrimaryMixPorts(bool connectedOnly, bool singlePort) const {
191     return findMixPorts(false /*isInput*/, connectedOnly, singlePort, [&](const AudioPort& port) {
192         return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
193                                     AudioOutputFlags::PRIMARY);
194     });
195 }
196 
getMmapOutMixPorts(bool connectedOnly,bool singlePort) const197 std::vector<AudioPort> ModuleConfig::getMmapOutMixPorts(bool connectedOnly, bool singlePort) const {
198     return findMixPorts(false /*isInput*/, connectedOnly, singlePort, [&](const AudioPort& port) {
199         return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
200                                     AudioOutputFlags::MMAP_NOIRQ);
201     });
202 }
203 
getMmapInMixPorts(bool connectedOnly,bool singlePort) const204 std::vector<AudioPort> ModuleConfig::getMmapInMixPorts(bool connectedOnly, bool singlePort) const {
205     return findMixPorts(true /*isInput*/, connectedOnly, singlePort, [&](const AudioPort& port) {
206         return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::input>(),
207                                     AudioInputFlags::MMAP_NOIRQ);
208     });
209 }
210 
getRemoteSubmixPorts(bool isInput,bool singlePort) const211 std::vector<AudioPort> ModuleConfig::getRemoteSubmixPorts(bool isInput, bool singlePort) const {
212     AudioDeviceType deviceType = isInput ? AudioDeviceType::IN_SUBMIX : AudioDeviceType::OUT_SUBMIX;
213     auto ports = getAudioPortsForDeviceTypes(std::vector<AudioDeviceType>{deviceType},
214                                              AudioDeviceDescription::CONNECTION_VIRTUAL);
215     if (singlePort) {
216         if (!ports.empty()) ports.resize(1);
217     }
218     return ports;
219 }
220 
getConnectedDevicesPortsForMixPort(bool isInput,const AudioPortConfig & mixPortConfig) const221 std::vector<AudioPort> ModuleConfig::getConnectedDevicesPortsForMixPort(
222         bool isInput, const AudioPortConfig& mixPortConfig) const {
223     const auto mixPortIt = findById<AudioPort>(mPorts, mixPortConfig.portId);
224     if (mixPortIt != mPorts.end()) {
225         return getConnectedDevicesPortsForMixPort(isInput, *mixPortIt);
226     }
227     return {};
228 }
229 
getConnectedSinkDevicesPortsForMixPort(const AudioPort & mixPort) const230 std::vector<AudioPort> ModuleConfig::getConnectedSinkDevicesPortsForMixPort(
231         const AudioPort& mixPort) const {
232     std::vector<AudioPort> result;
233     std::set<int32_t> connectedSinkDevicePorts = getConnectedSinkDevicePorts();
234     for (const auto& route : mRoutes) {
235         if ((connectedSinkDevicePorts.count(route.sinkPortId) != 0) &&
236             std::find(route.sourcePortIds.begin(), route.sourcePortIds.end(), mixPort.id) !=
237                     route.sourcePortIds.end()) {
238             const auto devicePortIt = findById<AudioPort>(mPorts, route.sinkPortId);
239             if (devicePortIt != mPorts.end()) result.push_back(*devicePortIt);
240         }
241     }
242     return result;
243 }
244 
getConnectedSourceDevicesPortsForMixPort(const AudioPort & mixPort) const245 std::vector<AudioPort> ModuleConfig::getConnectedSourceDevicesPortsForMixPort(
246         const AudioPort& mixPort) const {
247     std::vector<AudioPort> result;
248     std::set<int32_t> connectedSourceDevicePorts = getConnectedSourceDevicePorts();
249     for (const auto& route : mRoutes) {
250         if (route.sinkPortId == mixPort.id) {
251             for (const auto srcId : route.sourcePortIds) {
252                 if (connectedSourceDevicePorts.count(srcId) != 0) {
253                     const auto devicePortIt = findById<AudioPort>(mPorts, srcId);
254                     if (devicePortIt != mPorts.end()) result.push_back(*devicePortIt);
255                 }
256             }
257         }
258     }
259     return result;
260 }
261 
getSourceMixPortForConnectedDevice() const262 std::optional<AudioPort> ModuleConfig::getSourceMixPortForConnectedDevice() const {
263     std::set<int32_t> connectedSinkDevicePorts = getConnectedSinkDevicePorts();
264     for (const auto& route : mRoutes) {
265         if (connectedSinkDevicePorts.count(route.sinkPortId) != 0) {
266             const auto mixPortIt = findById<AudioPort>(mPorts, route.sourcePortIds[0]);
267             if (mixPortIt != mPorts.end()) return *mixPortIt;
268         }
269     }
270     return {};
271 }
272 
getRoutableDevicePortsForMixPort(const AudioPort & port,bool connectedOnly) const273 std::vector<AudioPort> ModuleConfig::getRoutableDevicePortsForMixPort(const AudioPort& port,
274                                                                       bool connectedOnly) const {
275     std::set<int32_t> portIds = findRoutablePortIds(port.id);
276     const bool isInput = port.flags.getTag() == AudioIoFlags::input;
277     std::set<int32_t> devicePortIds;
278     if (connectedOnly) {
279         devicePortIds = isInput ? getConnectedSourceDevicePorts() : getConnectedSinkDevicePorts();
280     } else {
281         devicePortIds = portIds;
282     }
283     std::vector<AudioPort> result;
284     std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
285         return port.ext.getTag() == AudioPortExt::Tag::device && portIds.count(port.id) > 0 &&
286                devicePortIds.count(port.id) > 0;
287     });
288     return result;
289 }
290 
getRoutableMixPortsForDevicePort(const AudioPort & port,bool connectedOnly) const291 std::vector<AudioPort> ModuleConfig::getRoutableMixPortsForDevicePort(const AudioPort& port,
292                                                                       bool connectedOnly) const {
293     std::set<int32_t> portIds = findRoutablePortIds(port.id);
294     const bool isInput = port.flags.getTag() == AudioIoFlags::input;
295     return findMixPorts(isInput, connectedOnly, false /*singlePort*/,
296                         [&portIds](const AudioPort& p) { return portIds.count(p.id) > 0; });
297 }
298 
getNonRoutableSrcSinkPair(bool isInput) const299 std::optional<ModuleConfig::SrcSinkPair> ModuleConfig::getNonRoutableSrcSinkPair(
300         bool isInput) const {
301     const auto mixPorts = getMixPorts(isInput, false /*connectedOnly*/);
302     std::set<std::pair<int32_t, int32_t>> allowedRoutes;
303     for (const auto& route : mRoutes) {
304         for (const auto srcPortId : route.sourcePortIds) {
305             allowedRoutes.emplace(std::make_pair(srcPortId, route.sinkPortId));
306         }
307     }
308     auto make_pair = [isInput](auto& device, auto& mix) {
309         return isInput ? std::make_pair(device, mix) : std::make_pair(mix, device);
310     };
311     for (const auto portId :
312          isInput ? getConnectedSourceDevicePorts() : getConnectedSinkDevicePorts()) {
313         const auto devicePortIt = findById<AudioPort>(mPorts, portId);
314         if (devicePortIt == mPorts.end()) continue;
315         auto devicePortConfig = getSingleConfigForDevicePort(*devicePortIt);
316         for (const auto& mixPort : mixPorts) {
317             if (std::find(allowedRoutes.begin(), allowedRoutes.end(),
318                           make_pair(portId, mixPort.id)) == allowedRoutes.end()) {
319                 auto mixPortConfig = getSingleConfigForMixPort(isInput, mixPort);
320                 if (mixPortConfig.has_value()) {
321                     return make_pair(devicePortConfig, mixPortConfig.value());
322                 }
323             }
324         }
325     }
326     return {};
327 }
328 
getRoutableSrcSinkPair(bool isInput) const329 std::optional<ModuleConfig::SrcSinkPair> ModuleConfig::getRoutableSrcSinkPair(bool isInput) const {
330     if (isInput) {
331         std::set<int32_t> connectedSourceDevicePorts = getConnectedSourceDevicePorts();
332         for (const auto& route : mRoutes) {
333             auto srcPortIdIt = std::find_if(
334                     route.sourcePortIds.begin(), route.sourcePortIds.end(),
335                     [&](const auto& portId) { return connectedSourceDevicePorts.count(portId); });
336             if (srcPortIdIt == route.sourcePortIds.end()) continue;
337             const auto devicePortIt = findById<AudioPort>(mPorts, *srcPortIdIt);
338             const auto mixPortIt = findById<AudioPort>(mPorts, route.sinkPortId);
339             if (devicePortIt == mPorts.end() || mixPortIt == mPorts.end()) continue;
340             auto devicePortConfig = getSingleConfigForDevicePort(*devicePortIt);
341             auto mixPortConfig = getSingleConfigForMixPort(isInput, *mixPortIt);
342             if (!mixPortConfig.has_value()) continue;
343             return std::make_pair(devicePortConfig, mixPortConfig.value());
344         }
345     } else {
346         std::set<int32_t> connectedSinkDevicePorts = getConnectedSinkDevicePorts();
347         for (const auto& route : mRoutes) {
348             if (connectedSinkDevicePorts.count(route.sinkPortId) == 0) continue;
349             const auto mixPortIt = findById<AudioPort>(mPorts, route.sourcePortIds[0]);
350             const auto devicePortIt = findById<AudioPort>(mPorts, route.sinkPortId);
351             if (devicePortIt == mPorts.end() || mixPortIt == mPorts.end()) continue;
352             auto mixPortConfig = getSingleConfigForMixPort(isInput, *mixPortIt);
353             auto devicePortConfig = getSingleConfigForDevicePort(*devicePortIt);
354             if (!mixPortConfig.has_value()) continue;
355             return std::make_pair(mixPortConfig.value(), devicePortConfig);
356         }
357     }
358     return {};
359 }
360 
getRoutableSrcSinkGroups(bool isInput) const361 std::vector<ModuleConfig::SrcSinkGroup> ModuleConfig::getRoutableSrcSinkGroups(bool isInput) const {
362     std::vector<SrcSinkGroup> result;
363     if (isInput) {
364         std::set<int32_t> connectedSourceDevicePorts = getConnectedSourceDevicePorts();
365         for (const auto& route : mRoutes) {
366             std::vector<int32_t> srcPortIds;
367             std::copy_if(route.sourcePortIds.begin(), route.sourcePortIds.end(),
368                          std::back_inserter(srcPortIds), [&](const auto& portId) {
369                              return connectedSourceDevicePorts.count(portId);
370                          });
371             if (srcPortIds.empty()) continue;
372             const auto mixPortIt = findById<AudioPort>(mPorts, route.sinkPortId);
373             if (mixPortIt == mPorts.end()) continue;
374             auto mixPortConfig = getSingleConfigForMixPort(isInput, *mixPortIt);
375             if (!mixPortConfig.has_value()) continue;
376             std::vector<SrcSinkPair> pairs;
377             for (const auto srcPortId : srcPortIds) {
378                 const auto devicePortIt = findById<AudioPort>(mPorts, srcPortId);
379                 if (devicePortIt == mPorts.end()) continue;
380                 // Using all configs for every source would be too much.
381                 auto devicePortConfig = getSingleConfigForDevicePort(*devicePortIt);
382                 pairs.emplace_back(devicePortConfig, mixPortConfig.value());
383             }
384             if (!pairs.empty()) {
385                 result.emplace_back(route, std::move(pairs));
386             }
387         }
388     } else {
389         std::set<int32_t> connectedSinkDevicePorts = getConnectedSinkDevicePorts();
390         for (const auto& route : mRoutes) {
391             if (connectedSinkDevicePorts.count(route.sinkPortId) == 0) continue;
392             const auto devicePortIt = findById<AudioPort>(mPorts, route.sinkPortId);
393             if (devicePortIt == mPorts.end()) continue;
394             auto devicePortConfig = getSingleConfigForDevicePort(*devicePortIt);
395             std::vector<SrcSinkPair> pairs;
396             for (const auto srcPortId : route.sourcePortIds) {
397                 const auto mixPortIt = findById<AudioPort>(mPorts, srcPortId);
398                 if (mixPortIt == mPorts.end()) continue;
399                 // Using all configs for every source would be too much.
400                 auto mixPortConfig = getSingleConfigForMixPort(isInput, *mixPortIt);
401                 if (mixPortConfig.has_value()) {
402                     pairs.emplace_back(mixPortConfig.value(), devicePortConfig);
403                 }
404             }
405             if (!pairs.empty()) {
406                 result.emplace_back(route, std::move(pairs));
407             }
408         }
409     }
410     return result;
411 }
412 
toString() const413 std::string ModuleConfig::toString() const {
414     std::string result;
415     result.append("Ports: ");
416     result.append(android::internal::ToString(mPorts));
417     result.append("\nInitial configs: ");
418     result.append(android::internal::ToString(mInitialConfigs));
419     result.append("\nAttached sink device ports: ");
420     result.append(android::internal::ToString(mAttachedSinkDevicePorts));
421     result.append("\nAttached source device ports: ");
422     result.append(android::internal::ToString(mAttachedSourceDevicePorts));
423     result.append("\nExternal device ports: ");
424     result.append(android::internal::ToString(mExternalDevicePorts));
425     result.append("\nConnected external device ports: ");
426     result.append(android::internal::ToString(getConnectedExternalDevicePorts()));
427     result.append("\nRoutes: ");
428     result.append(android::internal::ToString(mRoutes));
429     return result;
430 }
431 
combineAudioConfigs(const AudioPort & port,const AudioProfile & profile,std::vector<AudioPortConfig> * result)432 static size_t combineAudioConfigs(const AudioPort& port, const AudioProfile& profile,
433                                   std::vector<AudioPortConfig>* result) {
434     const size_t newConfigCount = profile.channelMasks.size() * profile.sampleRates.size();
435     result->reserve(result->capacity() + newConfigCount);
436     for (auto channelMask : profile.channelMasks) {
437         for (auto sampleRate : profile.sampleRates) {
438             AudioPortConfig config{};
439             config.portId = port.id;
440             Int sr;
441             sr.value = sampleRate;
442             config.sampleRate = sr;
443             config.channelMask = channelMask;
444             config.format = profile.format;
445             config.flags = port.flags;
446             config.ext = port.ext;
447             result->push_back(std::move(config));
448         }
449     }
450     return newConfigCount;
451 }
452 
isDynamicProfile(const AudioProfile & profile)453 static bool isDynamicProfile(const AudioProfile& profile) {
454     return (profile.format.type == AudioFormatType::DEFAULT && profile.format.encoding.empty()) ||
455            profile.sampleRates.empty() || profile.channelMasks.empty();
456 }
457 
findMixPorts(bool isInput,bool connectedOnly,bool singlePort,const std::function<bool (const AudioPort &)> & pred) const458 std::vector<AudioPort> ModuleConfig::findMixPorts(
459         bool isInput, bool connectedOnly, bool singlePort,
460         const std::function<bool(const AudioPort&)>& pred) const {
461     std::vector<AudioPort> result;
462     const auto mixPorts = getMixPorts(isInput, connectedOnly);
463     for (auto mixPortIt = mixPorts.begin(); mixPortIt != mixPorts.end();) {
464         mixPortIt = std::find_if(mixPortIt, mixPorts.end(), pred);
465         if (mixPortIt == mixPorts.end()) break;
466         result.push_back(*mixPortIt++);
467         if (singlePort) break;
468     }
469     return result;
470 }
471 
findRoutablePortIds(int32_t portId) const472 std::set<int32_t> ModuleConfig::findRoutablePortIds(int32_t portId) const {
473     std::set<int32_t> portIds;
474     for (const auto& route : mRoutes) {
475         if (portId == route.sinkPortId) {
476             portIds.insert(route.sourcePortIds.begin(), route.sourcePortIds.end());
477         } else if (auto it = std::find(route.sourcePortIds.begin(), route.sourcePortIds.end(),
478                                        portId);
479                    it != route.sourcePortIds.end()) {
480             portIds.insert(route.sinkPortId);
481         }
482     }
483     return portIds;
484 }
485 
generateAudioMixPortConfigs(const std::vector<AudioPort> & ports,bool isInput,bool singleProfile) const486 std::vector<AudioPortConfig> ModuleConfig::generateAudioMixPortConfigs(
487         const std::vector<AudioPort>& ports, bool isInput, bool singleProfile) const {
488     std::vector<AudioPortConfig> result;
489     for (const auto& mixPort : ports) {
490         if (getConnectedDevicesPortsForMixPort(isInput, mixPort).empty()) {
491             continue;
492         }
493         for (const auto& profile : mixPort.profiles) {
494             if (isDynamicProfile(profile)) continue;
495             combineAudioConfigs(mixPort, profile, &result);
496             if (singleProfile && !result.empty()) {
497                 result.resize(1);
498                 return result;
499             }
500         }
501     }
502     return result;
503 }
504 
generateAudioDevicePortConfigs(const std::vector<AudioPort> & ports,bool singleProfile) const505 std::vector<AudioPortConfig> ModuleConfig::generateAudioDevicePortConfigs(
506         const std::vector<AudioPort>& ports, bool singleProfile) const {
507     std::vector<AudioPortConfig> result;
508     for (const auto& devicePort : ports) {
509         const size_t resultSizeBefore = result.size();
510         for (const auto& profile : devicePort.profiles) {
511             combineAudioConfigs(devicePort, profile, &result);
512             if (singleProfile && !result.empty()) {
513                 result.resize(1);
514                 return result;
515             }
516         }
517         if (resultSizeBefore == result.size()) {
518             std::copy_if(mInitialConfigs.begin(), mInitialConfigs.end(), std::back_inserter(result),
519                          [&](const auto& config) { return config.portId == devicePort.id; });
520             if (resultSizeBefore == result.size()) {
521                 AudioPortConfig empty;
522                 empty.portId = devicePort.id;
523                 empty.ext = devicePort.ext;
524                 result.push_back(empty);
525             }
526         }
527         if (singleProfile) return result;
528     }
529     return result;
530 }
531 
getPort(int32_t portId)532 std::optional<AudioPort> ModuleConfig::getPort(int32_t portId) {
533     auto portsIt = findById(mPorts, portId);
534     return portsIt != mPorts.end() ? std::optional<AudioPort>(*portsIt) : std::nullopt;
535 }
536 
onExternalDeviceConnected(IModule * module,const AudioPort & port)537 ndk::ScopedAStatus ModuleConfig::onExternalDeviceConnected(IModule* module, const AudioPort& port) {
538     RETURN_STATUS_IF_ERROR(module->getAudioPorts(&mPorts));
539     RETURN_STATUS_IF_ERROR(module->getAudioRoutes(&mRoutes));
540 
541     // Validate port is present in module
542     if (std::find(mPorts.begin(), mPorts.end(), port) == mPorts.end()) {
543         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
544     }
545 
546     if (port.flags.getTag() == aidl::android::media::audio::common::AudioIoFlags::Tag::input) {
547         mConnectedExternalSourceDevicePorts.insert(port.id);
548     } else {
549         mConnectedExternalSinkDevicePorts.insert(port.id);
550     }
551     return ndk::ScopedAStatus::ok();
552 }
553 
onExternalDeviceDisconnected(IModule * module,const AudioPort & port)554 ndk::ScopedAStatus ModuleConfig::onExternalDeviceDisconnected(IModule* module,
555                                                               const AudioPort& port) {
556     RETURN_STATUS_IF_ERROR(module->getAudioPorts(&mPorts));
557     RETURN_STATUS_IF_ERROR(module->getAudioRoutes(&mRoutes));
558 
559     if (port.flags.getTag() == aidl::android::media::audio::common::AudioIoFlags::Tag::input) {
560         mConnectedExternalSourceDevicePorts.erase(port.id);
561     } else {
562         mConnectedExternalSinkDevicePorts.erase(port.id);
563     }
564     return ndk::ScopedAStatus::ok();
565 }
566 
isMmapSupported() const567 bool ModuleConfig::isMmapSupported() const {
568     const std::vector<AudioPort> mmapOutMixPorts =
569             getMmapOutMixPorts(false /*connectedOnly*/, false /*singlePort*/);
570     const std::vector<AudioPort> mmapInMixPorts =
571             getMmapInMixPorts(false /*connectedOnly*/, false /*singlePort*/);
572     return !mmapOutMixPorts.empty() || !mmapInMixPorts.empty();
573 }
574