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