blob: 7e4b148259f3275db4620dd306f26e0e75aa2e75 [file] [log] [blame]
Mikhail Naganove5d747e2021-11-16 01:31:03 +00001/*
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>
Mikhail Naganov111e0ce2022-06-17 21:41:19 +000018#include <chrono>
Mikhail Naganove5d747e2021-11-16 01:31:03 +000019
Mikhail Naganova2c5ddf2022-09-12 22:57:14 +000020#include <Utils.h>
Mikhail Naganovf84d6402022-06-16 00:35:31 +000021#include <aidl/android/media/audio/common/AudioIoFlags.h>
22#include <aidl/android/media/audio/common/AudioOutputFlags.h>
Mikhail Naganove5d747e2021-11-16 01:31:03 +000023
24#include "ModuleConfig.h"
25
26using namespace android;
Mikhail Naganov111e0ce2022-06-17 21:41:19 +000027using namespace std::chrono_literals;
Mikhail Naganove5d747e2021-11-16 01:31:03 +000028
Mikhail Naganovf84d6402022-06-16 00:35:31 +000029using aidl::android::hardware::audio::core::IModule;
30using aidl::android::media::audio::common::AudioChannelLayout;
Mikhail Naganovef6bc742022-10-06 00:14:19 +000031using aidl::android::media::audio::common::AudioDeviceType;
Mikhail Naganov111e0ce2022-06-17 21:41:19 +000032using aidl::android::media::audio::common::AudioEncapsulationMode;
Mikhail Naganovf84d6402022-06-16 00:35:31 +000033using aidl::android::media::audio::common::AudioFormatDescription;
34using aidl::android::media::audio::common::AudioFormatType;
35using aidl::android::media::audio::common::AudioIoFlags;
Mikhail Naganov111e0ce2022-06-17 21:41:19 +000036using aidl::android::media::audio::common::AudioOffloadInfo;
Mikhail Naganovf84d6402022-06-16 00:35:31 +000037using aidl::android::media::audio::common::AudioOutputFlags;
38using aidl::android::media::audio::common::AudioPort;
39using aidl::android::media::audio::common::AudioPortConfig;
40using aidl::android::media::audio::common::AudioPortExt;
41using aidl::android::media::audio::common::AudioProfile;
Mikhail Naganov111e0ce2022-06-17 21:41:19 +000042using aidl::android::media::audio::common::AudioUsage;
Mikhail Naganovf84d6402022-06-16 00:35:31 +000043using aidl::android::media::audio::common::Int;
Mikhail Naganova2c5ddf2022-09-12 22:57:14 +000044using android::hardware::audio::common::isBitPositionFlagSet;
Mikhail Naganove5d747e2021-11-16 01:31:03 +000045
Mikhail Naganov111e0ce2022-06-17 21:41:19 +000046// static
47std::optional<AudioOffloadInfo> ModuleConfig::generateOffloadInfoIfNeeded(
48 const AudioPortConfig& portConfig) {
49 if (portConfig.flags.has_value() &&
50 portConfig.flags.value().getTag() == AudioIoFlags::Tag::output &&
Mikhail Naganova2c5ddf2022-09-12 22:57:14 +000051 isBitPositionFlagSet(portConfig.flags.value().get<AudioIoFlags::Tag::output>(),
52 AudioOutputFlags::COMPRESS_OFFLOAD)) {
Mikhail Naganov111e0ce2022-06-17 21:41:19 +000053 AudioOffloadInfo offloadInfo;
54 offloadInfo.base.sampleRate = portConfig.sampleRate.value().value;
55 offloadInfo.base.channelMask = portConfig.channelMask.value();
56 offloadInfo.base.format = portConfig.format.value();
57 offloadInfo.bitRatePerSecond = 256; // Arbitrary value.
58 offloadInfo.durationUs = std::chrono::microseconds(1min).count(); // Arbitrary value.
59 offloadInfo.usage = AudioUsage::MEDIA;
60 offloadInfo.encapsulationMode = AudioEncapsulationMode::NONE;
61 return offloadInfo;
62 }
63 return {};
64}
65
Mikhail Naganovef6bc742022-10-06 00:14:19 +000066// static
67std::vector<aidl::android::media::audio::common::AudioPort> ModuleConfig::getBuiltInMicPorts(
68 const std::vector<aidl::android::media::audio::common::AudioPort>& ports) {
69 std::vector<AudioPort> result;
70 std::copy_if(ports.begin(), ports.end(), std::back_inserter(result), [](const auto& port) {
71 const auto type = port.ext.template get<AudioPortExt::Tag::device>().device.type;
72 return type.connection.empty() && (type.type == AudioDeviceType::IN_MICROPHONE ||
73 type.type == AudioDeviceType::IN_MICROPHONE_BACK);
74 });
75 return result;
76}
77
Mikhail Naganove5d747e2021-11-16 01:31:03 +000078template <typename T>
79auto findById(const std::vector<T>& v, int32_t id) {
80 return std::find_if(v.begin(), v.end(), [&](const auto& p) { return p.id == id; });
81}
82
83ModuleConfig::ModuleConfig(IModule* module) {
84 mStatus = module->getAudioPorts(&mPorts);
85 if (!mStatus.isOk()) return;
86 for (const auto& port : mPorts) {
87 if (port.ext.getTag() != AudioPortExt::Tag::device) continue;
88 const auto& devicePort = port.ext.get<AudioPortExt::Tag::device>();
Mikhail Naganove5d747e2021-11-16 01:31:03 +000089 if (devicePort.device.type.connection.empty()) {
Mikhail Naganov00603d12022-05-02 22:52:13 +000090 const bool isInput = port.flags.getTag() == AudioIoFlags::Tag::input;
Mikhail Naganove5d747e2021-11-16 01:31:03 +000091 // Permanently attached device.
92 if (isInput) {
93 mAttachedSourceDevicePorts.insert(port.id);
94 } else {
95 mAttachedSinkDevicePorts.insert(port.id);
96 }
Mikhail Naganov00603d12022-05-02 22:52:13 +000097 } else if (port.profiles.empty()) {
98 mExternalDevicePorts.insert(port.id);
Mikhail Naganove5d747e2021-11-16 01:31:03 +000099 }
100 }
101 if (!mStatus.isOk()) return;
102 mStatus = module->getAudioRoutes(&mRoutes);
103 if (!mStatus.isOk()) return;
104 mStatus = module->getAudioPortConfigs(&mInitialConfigs);
105}
106
Mikhail Naganov00603d12022-05-02 22:52:13 +0000107std::vector<AudioPort> ModuleConfig::getAttachedDevicePorts() const {
108 std::vector<AudioPort> result;
109 std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
110 return mAttachedSinkDevicePorts.count(port.id) != 0 ||
111 mAttachedSourceDevicePorts.count(port.id) != 0;
112 });
113 return result;
114}
115
116std::vector<AudioPort> ModuleConfig::getExternalDevicePorts() const {
117 std::vector<AudioPort> result;
118 std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result),
119 [&](const auto& port) { return mExternalDevicePorts.count(port.id) != 0; });
120 return result;
121}
122
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000123std::vector<AudioPort> ModuleConfig::getInputMixPorts(bool attachedOnly) const {
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000124 std::vector<AudioPort> result;
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000125 std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000126 return port.ext.getTag() == AudioPortExt::Tag::mix &&
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000127 port.flags.getTag() == AudioIoFlags::Tag::input &&
128 (!attachedOnly || !getAttachedSourceDevicesPortsForMixPort(port).empty());
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000129 });
130 return result;
131}
132
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000133std::vector<AudioPort> ModuleConfig::getOutputMixPorts(bool attachedOnly) const {
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000134 std::vector<AudioPort> result;
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000135 std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000136 return port.ext.getTag() == AudioPortExt::Tag::mix &&
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000137 port.flags.getTag() == AudioIoFlags::Tag::output &&
138 (!attachedOnly || !getAttachedSinkDevicesPortsForMixPort(port).empty());
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000139 });
140 return result;
141}
142
Mikhail Naganov30301a42022-09-13 01:20:45 +0000143std::vector<AudioPort> ModuleConfig::getNonBlockingMixPorts(bool attachedOnly,
144 bool singlePort) const {
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000145 return findMixPorts(false /*isInput*/, attachedOnly, singlePort, [&](const AudioPort& port) {
Mikhail Naganov30301a42022-09-13 01:20:45 +0000146 return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000147 AudioOutputFlags::NON_BLOCKING);
Mikhail Naganov30301a42022-09-13 01:20:45 +0000148 });
149}
150
Mikhail Naganova2c5ddf2022-09-12 22:57:14 +0000151std::vector<AudioPort> ModuleConfig::getOffloadMixPorts(bool attachedOnly, bool singlePort) const {
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000152 return findMixPorts(false /*isInput*/, attachedOnly, singlePort, [&](const AudioPort& port) {
Mikhail Naganov30301a42022-09-13 01:20:45 +0000153 return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000154 AudioOutputFlags::COMPRESS_OFFLOAD);
155 });
156}
157
158std::vector<AudioPort> ModuleConfig::getPrimaryMixPorts(bool attachedOnly, bool singlePort) const {
159 return findMixPorts(false /*isInput*/, attachedOnly, singlePort, [&](const AudioPort& port) {
160 return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
161 AudioOutputFlags::PRIMARY);
Mikhail Naganov30301a42022-09-13 01:20:45 +0000162 });
Mikhail Naganova2c5ddf2022-09-12 22:57:14 +0000163}
164
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000165std::vector<AudioPort> ModuleConfig::getAttachedDevicesPortsForMixPort(
166 bool isInput, const AudioPortConfig& mixPortConfig) const {
167 const auto mixPortIt = findById<AudioPort>(mPorts, mixPortConfig.portId);
168 if (mixPortIt != mPorts.end()) {
169 return getAttachedDevicesPortsForMixPort(isInput, *mixPortIt);
170 }
171 return {};
172}
173
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000174std::vector<AudioPort> ModuleConfig::getAttachedSinkDevicesPortsForMixPort(
175 const AudioPort& mixPort) const {
176 std::vector<AudioPort> result;
177 for (const auto& route : mRoutes) {
178 if (mAttachedSinkDevicePorts.count(route.sinkPortId) != 0 &&
179 std::find(route.sourcePortIds.begin(), route.sourcePortIds.end(), mixPort.id) !=
180 route.sourcePortIds.end()) {
181 const auto devicePortIt = findById<AudioPort>(mPorts, route.sinkPortId);
182 if (devicePortIt != mPorts.end()) result.push_back(*devicePortIt);
183 }
184 }
185 return result;
186}
187
188std::vector<AudioPort> ModuleConfig::getAttachedSourceDevicesPortsForMixPort(
189 const AudioPort& mixPort) const {
190 std::vector<AudioPort> result;
191 for (const auto& route : mRoutes) {
192 if (route.sinkPortId == mixPort.id) {
193 for (const auto srcId : route.sourcePortIds) {
194 if (mAttachedSourceDevicePorts.count(srcId) != 0) {
195 const auto devicePortIt = findById<AudioPort>(mPorts, srcId);
196 if (devicePortIt != mPorts.end()) result.push_back(*devicePortIt);
197 }
198 }
199 }
200 }
201 return result;
202}
203
204std::optional<AudioPort> ModuleConfig::getSourceMixPortForAttachedDevice() const {
205 for (const auto& route : mRoutes) {
206 if (mAttachedSinkDevicePorts.count(route.sinkPortId) != 0) {
207 const auto mixPortIt = findById<AudioPort>(mPorts, route.sourcePortIds[0]);
208 if (mixPortIt != mPorts.end()) return *mixPortIt;
209 }
210 }
211 return {};
212}
213
214std::optional<ModuleConfig::SrcSinkPair> ModuleConfig::getNonRoutableSrcSinkPair(
215 bool isInput) const {
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000216 const auto mixPorts = getMixPorts(isInput, false /*attachedOnly*/);
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000217 std::set<std::pair<int32_t, int32_t>> allowedRoutes;
218 for (const auto& route : mRoutes) {
219 for (const auto srcPortId : route.sourcePortIds) {
220 allowedRoutes.emplace(std::make_pair(srcPortId, route.sinkPortId));
221 }
222 }
223 auto make_pair = [isInput](auto& device, auto& mix) {
224 return isInput ? std::make_pair(device, mix) : std::make_pair(mix, device);
225 };
226 for (const auto portId : isInput ? mAttachedSourceDevicePorts : mAttachedSinkDevicePorts) {
227 const auto devicePortIt = findById<AudioPort>(mPorts, portId);
228 if (devicePortIt == mPorts.end()) continue;
229 auto devicePortConfig = getSingleConfigForDevicePort(*devicePortIt);
230 for (const auto& mixPort : mixPorts) {
231 if (std::find(allowedRoutes.begin(), allowedRoutes.end(),
232 make_pair(portId, mixPort.id)) == allowedRoutes.end()) {
233 auto mixPortConfig = getSingleConfigForMixPort(isInput, mixPort);
234 if (mixPortConfig.has_value()) {
235 return make_pair(devicePortConfig, mixPortConfig.value());
236 }
237 }
238 }
239 }
240 return {};
241}
242
243std::optional<ModuleConfig::SrcSinkPair> ModuleConfig::getRoutableSrcSinkPair(bool isInput) const {
244 if (isInput) {
245 for (const auto& route : mRoutes) {
246 auto srcPortIdIt = std::find_if(
247 route.sourcePortIds.begin(), route.sourcePortIds.end(),
248 [&](const auto& portId) { return mAttachedSourceDevicePorts.count(portId); });
249 if (srcPortIdIt == route.sourcePortIds.end()) continue;
250 const auto devicePortIt = findById<AudioPort>(mPorts, *srcPortIdIt);
251 const auto mixPortIt = findById<AudioPort>(mPorts, route.sinkPortId);
252 if (devicePortIt == mPorts.end() || mixPortIt == mPorts.end()) continue;
253 auto devicePortConfig = getSingleConfigForDevicePort(*devicePortIt);
254 auto mixPortConfig = getSingleConfigForMixPort(isInput, *mixPortIt);
255 if (!mixPortConfig.has_value()) continue;
256 return std::make_pair(devicePortConfig, mixPortConfig.value());
257 }
258 } else {
259 for (const auto& route : mRoutes) {
260 if (mAttachedSinkDevicePorts.count(route.sinkPortId) == 0) continue;
261 const auto mixPortIt = findById<AudioPort>(mPorts, route.sourcePortIds[0]);
262 const auto devicePortIt = findById<AudioPort>(mPorts, route.sinkPortId);
263 if (devicePortIt == mPorts.end() || mixPortIt == mPorts.end()) continue;
264 auto mixPortConfig = getSingleConfigForMixPort(isInput, *mixPortIt);
265 auto devicePortConfig = getSingleConfigForDevicePort(*devicePortIt);
266 if (!mixPortConfig.has_value()) continue;
267 return std::make_pair(mixPortConfig.value(), devicePortConfig);
268 }
269 }
270 return {};
271}
272
273std::vector<ModuleConfig::SrcSinkGroup> ModuleConfig::getRoutableSrcSinkGroups(bool isInput) const {
274 std::vector<SrcSinkGroup> result;
275 if (isInput) {
276 for (const auto& route : mRoutes) {
277 std::vector<int32_t> srcPortIds;
278 std::copy_if(route.sourcePortIds.begin(), route.sourcePortIds.end(),
279 std::back_inserter(srcPortIds), [&](const auto& portId) {
280 return mAttachedSourceDevicePorts.count(portId);
281 });
282 if (srcPortIds.empty()) continue;
283 const auto mixPortIt = findById<AudioPort>(mPorts, route.sinkPortId);
284 if (mixPortIt == mPorts.end()) continue;
285 auto mixPortConfig = getSingleConfigForMixPort(isInput, *mixPortIt);
286 if (!mixPortConfig.has_value()) continue;
287 std::vector<SrcSinkPair> pairs;
288 for (const auto srcPortId : srcPortIds) {
289 const auto devicePortIt = findById<AudioPort>(mPorts, srcPortId);
290 if (devicePortIt == mPorts.end()) continue;
291 // Using all configs for every source would be too much.
292 auto devicePortConfig = getSingleConfigForDevicePort(*devicePortIt);
293 pairs.emplace_back(devicePortConfig, mixPortConfig.value());
294 }
295 if (!pairs.empty()) {
296 result.emplace_back(route, std::move(pairs));
297 }
298 }
299 } else {
300 for (const auto& route : mRoutes) {
301 if (mAttachedSinkDevicePorts.count(route.sinkPortId) == 0) continue;
302 const auto devicePortIt = findById<AudioPort>(mPorts, route.sinkPortId);
303 if (devicePortIt == mPorts.end()) continue;
304 auto devicePortConfig = getSingleConfigForDevicePort(*devicePortIt);
305 std::vector<SrcSinkPair> pairs;
306 for (const auto srcPortId : route.sourcePortIds) {
307 const auto mixPortIt = findById<AudioPort>(mPorts, srcPortId);
308 if (mixPortIt == mPorts.end()) continue;
309 // Using all configs for every source would be too much.
310 auto mixPortConfig = getSingleConfigForMixPort(isInput, *mixPortIt);
311 if (mixPortConfig.has_value()) {
312 pairs.emplace_back(mixPortConfig.value(), devicePortConfig);
313 }
314 }
315 if (!pairs.empty()) {
316 result.emplace_back(route, std::move(pairs));
317 }
318 }
319 }
320 return result;
321}
322
Mikhail Naganov00603d12022-05-02 22:52:13 +0000323std::string ModuleConfig::toString() const {
324 std::string result;
325 result.append("Ports: ");
326 result.append(android::internal::ToString(mPorts));
Mikhail Naganov16db9b72022-06-17 21:36:18 +0000327 result.append("\nInitial configs: ");
Mikhail Naganov00603d12022-05-02 22:52:13 +0000328 result.append(android::internal::ToString(mInitialConfigs));
Mikhail Naganov16db9b72022-06-17 21:36:18 +0000329 result.append("\nAttached sink device ports: ");
Mikhail Naganov00603d12022-05-02 22:52:13 +0000330 result.append(android::internal::ToString(mAttachedSinkDevicePorts));
Mikhail Naganov16db9b72022-06-17 21:36:18 +0000331 result.append("\nAttached source device ports: ");
Mikhail Naganov00603d12022-05-02 22:52:13 +0000332 result.append(android::internal::ToString(mAttachedSourceDevicePorts));
Mikhail Naganov16db9b72022-06-17 21:36:18 +0000333 result.append("\nExternal device ports: ");
Mikhail Naganov00603d12022-05-02 22:52:13 +0000334 result.append(android::internal::ToString(mExternalDevicePorts));
Mikhail Naganov16db9b72022-06-17 21:36:18 +0000335 result.append("\nRoutes: ");
Mikhail Naganov00603d12022-05-02 22:52:13 +0000336 result.append(android::internal::ToString(mRoutes));
337 return result;
338}
339
Mikhail Naganov111e0ce2022-06-17 21:41:19 +0000340static size_t combineAudioConfigs(const AudioPort& port, const AudioProfile& profile,
341 std::vector<AudioPortConfig>* result) {
342 const size_t newConfigCount = profile.channelMasks.size() * profile.sampleRates.size();
343 result->reserve(result->capacity() + newConfigCount);
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000344 for (auto channelMask : profile.channelMasks) {
345 for (auto sampleRate : profile.sampleRates) {
346 AudioPortConfig config{};
347 config.portId = port.id;
348 Int sr;
349 sr.value = sampleRate;
350 config.sampleRate = sr;
351 config.channelMask = channelMask;
352 config.format = profile.format;
Mikhail Naganov111e0ce2022-06-17 21:41:19 +0000353 config.flags = port.flags;
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000354 config.ext = port.ext;
Mikhail Naganov111e0ce2022-06-17 21:41:19 +0000355 result->push_back(std::move(config));
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000356 }
357 }
Mikhail Naganov111e0ce2022-06-17 21:41:19 +0000358 return newConfigCount;
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000359}
360
Mikhail Naganov111e0ce2022-06-17 21:41:19 +0000361static bool isDynamicProfile(const AudioProfile& profile) {
362 return (profile.format.type == AudioFormatType::DEFAULT && profile.format.encoding.empty()) ||
363 profile.sampleRates.empty() || profile.channelMasks.empty();
364}
365
Mikhail Naganov30301a42022-09-13 01:20:45 +0000366std::vector<AudioPort> ModuleConfig::findMixPorts(
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000367 bool isInput, bool attachedOnly, bool singlePort,
368 const std::function<bool(const AudioPort&)>& pred) const {
Mikhail Naganov30301a42022-09-13 01:20:45 +0000369 std::vector<AudioPort> result;
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000370 const auto mixPorts = getMixPorts(isInput, attachedOnly);
Mikhail Naganov30301a42022-09-13 01:20:45 +0000371 for (auto mixPortIt = mixPorts.begin(); mixPortIt != mixPorts.end();) {
372 mixPortIt = std::find_if(mixPortIt, mixPorts.end(), pred);
373 if (mixPortIt == mixPorts.end()) break;
374 result.push_back(*mixPortIt++);
375 if (singlePort) break;
376 }
377 return result;
378}
379
Mikhail Naganov111e0ce2022-06-17 21:41:19 +0000380std::vector<AudioPortConfig> ModuleConfig::generateAudioMixPortConfigs(
381 const std::vector<AudioPort>& ports, bool isInput, bool singleProfile) const {
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000382 std::vector<AudioPortConfig> result;
383 for (const auto& mixPort : ports) {
Mikhail Naganov111e0ce2022-06-17 21:41:19 +0000384 if (getAttachedDevicesPortsForMixPort(isInput, mixPort).empty()) {
385 continue;
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000386 }
387 for (const auto& profile : mixPort.profiles) {
Mikhail Naganov111e0ce2022-06-17 21:41:19 +0000388 if (isDynamicProfile(profile)) continue;
389 combineAudioConfigs(mixPort, profile, &result);
390 if (singleProfile && !result.empty()) {
391 result.resize(1);
392 return result;
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000393 }
394 }
395 }
396 return result;
397}
398
399std::vector<AudioPortConfig> ModuleConfig::generateAudioDevicePortConfigs(
400 const std::vector<AudioPort>& ports, bool singleProfile) const {
401 std::vector<AudioPortConfig> result;
402 for (const auto& devicePort : ports) {
403 const size_t resultSizeBefore = result.size();
404 for (const auto& profile : devicePort.profiles) {
Mikhail Naganov111e0ce2022-06-17 21:41:19 +0000405 combineAudioConfigs(devicePort, profile, &result);
406 if (singleProfile && !result.empty()) {
407 result.resize(1);
408 return result;
409 }
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000410 }
411 if (resultSizeBefore == result.size()) {
Mikhail Naganov00603d12022-05-02 22:52:13 +0000412 std::copy_if(mInitialConfigs.begin(), mInitialConfigs.end(), std::back_inserter(result),
413 [&](const auto& config) { return config.portId == devicePort.id; });
414 if (resultSizeBefore == result.size()) {
415 AudioPortConfig empty;
416 empty.portId = devicePort.id;
417 empty.ext = devicePort.ext;
418 result.push_back(empty);
419 }
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000420 }
421 if (singleProfile) return result;
422 }
423 return result;
424}