blob: 7d4cc7016e6efc10d254ffaa14684e9750559623 [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 Naganov6198ad32023-11-09 18:31:55 -080020#define LOG_TAG "VtsHalAudio.ModuleConfig"
21#include <android-base/logging.h>
22
Mikhail Naganova2c5ddf2022-09-12 22:57:14 +000023#include <Utils.h>
jiabin9a8e6862023-01-12 23:06:37 +000024#include <aidl/android/media/audio/common/AudioInputFlags.h>
Mikhail Naganovf84d6402022-06-16 00:35:31 +000025#include <aidl/android/media/audio/common/AudioIoFlags.h>
26#include <aidl/android/media/audio/common/AudioOutputFlags.h>
Mikhail Naganov0e128dd2023-09-13 18:01:18 -070027#include <error/expected_utils.h>
Mikhail Naganove5d747e2021-11-16 01:31:03 +000028
29#include "ModuleConfig.h"
30
31using namespace android;
Mikhail Naganov111e0ce2022-06-17 21:41:19 +000032using namespace std::chrono_literals;
Mikhail Naganove5d747e2021-11-16 01:31:03 +000033
Mikhail Naganov872d4a62023-03-09 18:19:01 -080034using aidl::android::hardware::audio::common::isBitPositionFlagSet;
Mikhail Naganovf84d6402022-06-16 00:35:31 +000035using aidl::android::hardware::audio::core::IModule;
36using aidl::android::media::audio::common::AudioChannelLayout;
David Lib089c0c2023-08-10 12:47:44 +080037using aidl::android::media::audio::common::AudioDeviceDescription;
Mikhail Naganovef6bc742022-10-06 00:14:19 +000038using aidl::android::media::audio::common::AudioDeviceType;
Mikhail Naganovf84d6402022-06-16 00:35:31 +000039using aidl::android::media::audio::common::AudioFormatDescription;
40using aidl::android::media::audio::common::AudioFormatType;
jiabin9a8e6862023-01-12 23:06:37 +000041using aidl::android::media::audio::common::AudioInputFlags;
Mikhail Naganovf84d6402022-06-16 00:35:31 +000042using aidl::android::media::audio::common::AudioIoFlags;
43using aidl::android::media::audio::common::AudioOutputFlags;
44using aidl::android::media::audio::common::AudioPort;
45using aidl::android::media::audio::common::AudioPortConfig;
46using aidl::android::media::audio::common::AudioPortExt;
47using aidl::android::media::audio::common::AudioProfile;
Mikhail Naganov111e0ce2022-06-17 21:41:19 +000048using aidl::android::media::audio::common::AudioUsage;
Mikhail Naganovf84d6402022-06-16 00:35:31 +000049using aidl::android::media::audio::common::Int;
Mikhail Naganove5d747e2021-11-16 01:31:03 +000050
Mikhail Naganov111e0ce2022-06-17 21:41:19 +000051// static
Shraddha Basantwani343db5e2023-08-23 12:39:15 +000052std::vector<aidl::android::media::audio::common::AudioPort>
53ModuleConfig::getAudioPortsForDeviceTypes(
54 const std::vector<aidl::android::media::audio::common::AudioPort>& ports,
55 const std::vector<AudioDeviceType>& deviceTypes, const std::string& connection) {
Mikhail Naganovef6bc742022-10-06 00:14:19 +000056 std::vector<AudioPort> result;
Shraddha Basantwani343db5e2023-08-23 12:39:15 +000057 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 }
Mikhail Naganovef6bc742022-10-06 00:14:19 +000068 return result;
69}
70
Mikhail Naganov95f22772023-10-25 08:44:47 -070071// static
72std::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
Mikhail Naganove5d747e2021-11-16 01:31:03 +000079template <typename T>
80auto 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
84ModuleConfig::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>();
Mikhail Naganove5d747e2021-11-16 01:31:03 +000090 if (devicePort.device.type.connection.empty()) {
Mikhail Naganov00603d12022-05-02 22:52:13 +000091 const bool isInput = port.flags.getTag() == AudioIoFlags::Tag::input;
Mikhail Naganove5d747e2021-11-16 01:31:03 +000092 // Permanently attached device.
93 if (isInput) {
94 mAttachedSourceDevicePorts.insert(port.id);
95 } else {
96 mAttachedSinkDevicePorts.insert(port.id);
97 }
Mikhail Naganov95f22772023-10-25 08:44:47 -070098 } else {
Mikhail Naganov00603d12022-05-02 22:52:13 +000099 mExternalDevicePorts.insert(port.id);
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000100 }
101 }
102 if (!mStatus.isOk()) return;
103 mStatus = module->getAudioRoutes(&mRoutes);
104 if (!mStatus.isOk()) return;
105 mStatus = module->getAudioPortConfigs(&mInitialConfigs);
106}
107
Mikhail Naganov00603d12022-05-02 22:52:13 +0000108std::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
Mikhail Naganov95f22772023-10-25 08:44:47 -0700117std::vector<aidl::android::media::audio::common::AudioPort>
118ModuleConfig::getAudioPortsForDeviceTypes(const std::vector<AudioDeviceType>& deviceTypes,
119 const std::string& connection) const {
120 return getAudioPortsForDeviceTypes(mPorts, deviceTypes, connection);
121}
122
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000123std::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
132std::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
140std::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
Mikhail Naganov00603d12022-05-02 22:52:13 +0000148std::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
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000155std::vector<AudioPort> ModuleConfig::getInputMixPorts(bool connectedOnly) const {
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000156 std::vector<AudioPort> result;
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000157 std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000158 return port.ext.getTag() == AudioPortExt::Tag::mix &&
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000159 port.flags.getTag() == AudioIoFlags::Tag::input &&
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000160 (!connectedOnly || !getConnectedSourceDevicesPortsForMixPort(port).empty());
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000161 });
162 return result;
163}
164
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000165std::vector<AudioPort> ModuleConfig::getOutputMixPorts(bool connectedOnly) const {
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000166 std::vector<AudioPort> result;
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000167 std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000168 return port.ext.getTag() == AudioPortExt::Tag::mix &&
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000169 port.flags.getTag() == AudioIoFlags::Tag::output &&
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000170 (!connectedOnly || !getConnectedSinkDevicesPortsForMixPort(port).empty());
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000171 });
172 return result;
173}
174
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000175std::vector<AudioPort> ModuleConfig::getNonBlockingMixPorts(bool connectedOnly,
Mikhail Naganov30301a42022-09-13 01:20:45 +0000176 bool singlePort) const {
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000177 return findMixPorts(false /*isInput*/, connectedOnly, singlePort, [&](const AudioPort& port) {
Mikhail Naganov30301a42022-09-13 01:20:45 +0000178 return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000179 AudioOutputFlags::NON_BLOCKING);
Mikhail Naganov30301a42022-09-13 01:20:45 +0000180 });
181}
182
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000183std::vector<AudioPort> ModuleConfig::getOffloadMixPorts(bool connectedOnly, bool singlePort) const {
184 return findMixPorts(false /*isInput*/, connectedOnly, singlePort, [&](const AudioPort& port) {
Mikhail Naganov30301a42022-09-13 01:20:45 +0000185 return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000186 AudioOutputFlags::COMPRESS_OFFLOAD);
187 });
188}
189
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000190std::vector<AudioPort> ModuleConfig::getPrimaryMixPorts(bool connectedOnly, bool singlePort) const {
191 return findMixPorts(false /*isInput*/, connectedOnly, singlePort, [&](const AudioPort& port) {
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000192 return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
193 AudioOutputFlags::PRIMARY);
Mikhail Naganov30301a42022-09-13 01:20:45 +0000194 });
Mikhail Naganova2c5ddf2022-09-12 22:57:14 +0000195}
196
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000197std::vector<AudioPort> ModuleConfig::getMmapOutMixPorts(bool connectedOnly, bool singlePort) const {
198 return findMixPorts(false /*isInput*/, connectedOnly, singlePort, [&](const AudioPort& port) {
jiabin9a8e6862023-01-12 23:06:37 +0000199 return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
200 AudioOutputFlags::MMAP_NOIRQ);
201 });
202}
203
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000204std::vector<AudioPort> ModuleConfig::getMmapInMixPorts(bool connectedOnly, bool singlePort) const {
205 return findMixPorts(true /*isInput*/, connectedOnly, singlePort, [&](const AudioPort& port) {
jiabin9a8e6862023-01-12 23:06:37 +0000206 return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::input>(),
207 AudioInputFlags::MMAP_NOIRQ);
208 });
209}
210
Mikhail Naganov95f22772023-10-25 08:44:47 -0700211std::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
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000221std::vector<AudioPort> ModuleConfig::getConnectedDevicesPortsForMixPort(
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000222 bool isInput, const AudioPortConfig& mixPortConfig) const {
223 const auto mixPortIt = findById<AudioPort>(mPorts, mixPortConfig.portId);
224 if (mixPortIt != mPorts.end()) {
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000225 return getConnectedDevicesPortsForMixPort(isInput, *mixPortIt);
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000226 }
227 return {};
228}
229
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000230std::vector<AudioPort> ModuleConfig::getConnectedSinkDevicesPortsForMixPort(
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000231 const AudioPort& mixPort) const {
232 std::vector<AudioPort> result;
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000233 std::set<int32_t> connectedSinkDevicePorts = getConnectedSinkDevicePorts();
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000234 for (const auto& route : mRoutes) {
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000235 if ((connectedSinkDevicePorts.count(route.sinkPortId) != 0) &&
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000236 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
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000245std::vector<AudioPort> ModuleConfig::getConnectedSourceDevicesPortsForMixPort(
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000246 const AudioPort& mixPort) const {
247 std::vector<AudioPort> result;
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000248 std::set<int32_t> connectedSourceDevicePorts = getConnectedSourceDevicePorts();
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000249 for (const auto& route : mRoutes) {
250 if (route.sinkPortId == mixPort.id) {
251 for (const auto srcId : route.sourcePortIds) {
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000252 if (connectedSourceDevicePorts.count(srcId) != 0) {
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000253 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
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000262std::optional<AudioPort> ModuleConfig::getSourceMixPortForConnectedDevice() const {
263 std::set<int32_t> connectedSinkDevicePorts = getConnectedSinkDevicePorts();
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000264 for (const auto& route : mRoutes) {
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000265 if (connectedSinkDevicePorts.count(route.sinkPortId) != 0) {
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000266 const auto mixPortIt = findById<AudioPort>(mPorts, route.sourcePortIds[0]);
267 if (mixPortIt != mPorts.end()) return *mixPortIt;
268 }
269 }
270 return {};
271}
272
Mikhail Naganov95f22772023-10-25 08:44:47 -0700273std::vector<AudioPort> ModuleConfig::getRoutableDevicePortsForMixPort(const AudioPort& port,
274 bool connectedOnly) const {
275 std::set<int32_t> portIds = findRoutablePortIds(port.id);
Mikhail Naganov84bcc042023-10-05 17:36:57 -0700276 const bool isInput = port.flags.getTag() == AudioIoFlags::input;
Mikhail Naganov95f22772023-10-25 08:44:47 -0700277 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
291std::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*/,
Mikhail Naganov84bcc042023-10-05 17:36:57 -0700296 [&portIds](const AudioPort& p) { return portIds.count(p.id) > 0; });
297}
298
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000299std::optional<ModuleConfig::SrcSinkPair> ModuleConfig::getNonRoutableSrcSinkPair(
300 bool isInput) const {
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000301 const auto mixPorts = getMixPorts(isInput, false /*connectedOnly*/);
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000302 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 };
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000311 for (const auto portId :
312 isInput ? getConnectedSourceDevicePorts() : getConnectedSinkDevicePorts()) {
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000313 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
329std::optional<ModuleConfig::SrcSinkPair> ModuleConfig::getRoutableSrcSinkPair(bool isInput) const {
330 if (isInput) {
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000331 std::set<int32_t> connectedSourceDevicePorts = getConnectedSourceDevicePorts();
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000332 for (const auto& route : mRoutes) {
333 auto srcPortIdIt = std::find_if(
334 route.sourcePortIds.begin(), route.sourcePortIds.end(),
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000335 [&](const auto& portId) { return connectedSourceDevicePorts.count(portId); });
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000336 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 {
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000346 std::set<int32_t> connectedSinkDevicePorts = getConnectedSinkDevicePorts();
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000347 for (const auto& route : mRoutes) {
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000348 if (connectedSinkDevicePorts.count(route.sinkPortId) == 0) continue;
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000349 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
361std::vector<ModuleConfig::SrcSinkGroup> ModuleConfig::getRoutableSrcSinkGroups(bool isInput) const {
362 std::vector<SrcSinkGroup> result;
363 if (isInput) {
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000364 std::set<int32_t> connectedSourceDevicePorts = getConnectedSourceDevicePorts();
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000365 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) {
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000369 return connectedSourceDevicePorts.count(portId);
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000370 });
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 {
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000389 std::set<int32_t> connectedSinkDevicePorts = getConnectedSinkDevicePorts();
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000390 for (const auto& route : mRoutes) {
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000391 if (connectedSinkDevicePorts.count(route.sinkPortId) == 0) continue;
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000392 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
Mikhail Naganov00603d12022-05-02 22:52:13 +0000413std::string ModuleConfig::toString() const {
414 std::string result;
415 result.append("Ports: ");
416 result.append(android::internal::ToString(mPorts));
Mikhail Naganov16db9b72022-06-17 21:36:18 +0000417 result.append("\nInitial configs: ");
Mikhail Naganov00603d12022-05-02 22:52:13 +0000418 result.append(android::internal::ToString(mInitialConfigs));
Mikhail Naganov16db9b72022-06-17 21:36:18 +0000419 result.append("\nAttached sink device ports: ");
Mikhail Naganov00603d12022-05-02 22:52:13 +0000420 result.append(android::internal::ToString(mAttachedSinkDevicePorts));
Mikhail Naganov16db9b72022-06-17 21:36:18 +0000421 result.append("\nAttached source device ports: ");
Mikhail Naganov00603d12022-05-02 22:52:13 +0000422 result.append(android::internal::ToString(mAttachedSourceDevicePorts));
Mikhail Naganov16db9b72022-06-17 21:36:18 +0000423 result.append("\nExternal device ports: ");
Mikhail Naganov00603d12022-05-02 22:52:13 +0000424 result.append(android::internal::ToString(mExternalDevicePorts));
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000425 result.append("\nConnected external device ports: ");
426 result.append(android::internal::ToString(getConnectedExternalDevicePorts()));
Mikhail Naganov16db9b72022-06-17 21:36:18 +0000427 result.append("\nRoutes: ");
Mikhail Naganov00603d12022-05-02 22:52:13 +0000428 result.append(android::internal::ToString(mRoutes));
429 return result;
430}
431
Mikhail Naganov111e0ce2022-06-17 21:41:19 +0000432static 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);
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000436 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;
Mikhail Naganov111e0ce2022-06-17 21:41:19 +0000445 config.flags = port.flags;
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000446 config.ext = port.ext;
Mikhail Naganov111e0ce2022-06-17 21:41:19 +0000447 result->push_back(std::move(config));
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000448 }
449 }
Mikhail Naganov111e0ce2022-06-17 21:41:19 +0000450 return newConfigCount;
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000451}
452
Mikhail Naganov111e0ce2022-06-17 21:41:19 +0000453static 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
Mikhail Naganov30301a42022-09-13 01:20:45 +0000458std::vector<AudioPort> ModuleConfig::findMixPorts(
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000459 bool isInput, bool connectedOnly, bool singlePort,
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000460 const std::function<bool(const AudioPort&)>& pred) const {
Mikhail Naganov30301a42022-09-13 01:20:45 +0000461 std::vector<AudioPort> result;
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000462 const auto mixPorts = getMixPorts(isInput, connectedOnly);
Mikhail Naganov30301a42022-09-13 01:20:45 +0000463 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
Mikhail Naganov95f22772023-10-25 08:44:47 -0700472std::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
Mikhail Naganov111e0ce2022-06-17 21:41:19 +0000486std::vector<AudioPortConfig> ModuleConfig::generateAudioMixPortConfigs(
487 const std::vector<AudioPort>& ports, bool isInput, bool singleProfile) const {
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000488 std::vector<AudioPortConfig> result;
489 for (const auto& mixPort : ports) {
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000490 if (getConnectedDevicesPortsForMixPort(isInput, mixPort).empty()) {
Mikhail Naganov111e0ce2022-06-17 21:41:19 +0000491 continue;
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000492 }
493 for (const auto& profile : mixPort.profiles) {
Mikhail Naganov111e0ce2022-06-17 21:41:19 +0000494 if (isDynamicProfile(profile)) continue;
495 combineAudioConfigs(mixPort, profile, &result);
496 if (singleProfile && !result.empty()) {
497 result.resize(1);
498 return result;
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000499 }
500 }
501 }
502 return result;
503}
504
505std::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) {
Mikhail Naganov111e0ce2022-06-17 21:41:19 +0000511 combineAudioConfigs(devicePort, profile, &result);
512 if (singleProfile && !result.empty()) {
513 result.resize(1);
514 return result;
515 }
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000516 }
517 if (resultSizeBefore == result.size()) {
Mikhail Naganov00603d12022-05-02 22:52:13 +0000518 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 }
Mikhail Naganove5d747e2021-11-16 01:31:03 +0000526 }
527 if (singleProfile) return result;
528 }
529 return result;
530}
jiabinb76981e2023-01-18 00:58:30 +0000531
Mikhail Naganova62c5df2024-04-17 17:10:31 -0700532std::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
Mikhail Naganov0e128dd2023-09-13 18:01:18 -0700537ndk::ScopedAStatus ModuleConfig::onExternalDeviceConnected(IModule* module, const AudioPort& port) {
538 RETURN_STATUS_IF_ERROR(module->getAudioPorts(&mPorts));
539 RETURN_STATUS_IF_ERROR(module->getAudioRoutes(&mRoutes));
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000540
541 // Validate port is present in module
542 if (std::find(mPorts.begin(), mPorts.end(), port) == mPorts.end()) {
Mikhail Naganov0e128dd2023-09-13 18:01:18 -0700543 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000544 }
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 }
Mikhail Naganov0e128dd2023-09-13 18:01:18 -0700551 return ndk::ScopedAStatus::ok();
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000552}
553
Mikhail Naganov0e128dd2023-09-13 18:01:18 -0700554ndk::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));
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000558
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 }
Mikhail Naganov0e128dd2023-09-13 18:01:18 -0700564 return ndk::ScopedAStatus::ok();
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000565}
566
jiabinb76981e2023-01-18 00:58:30 +0000567bool ModuleConfig::isMmapSupported() const {
568 const std::vector<AudioPort> mmapOutMixPorts =
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000569 getMmapOutMixPorts(false /*connectedOnly*/, false /*singlePort*/);
jiabinb76981e2023-01-18 00:58:30 +0000570 const std::vector<AudioPort> mmapInMixPorts =
Shraddha Basantwani343db5e2023-08-23 12:39:15 +0000571 getMmapInMixPorts(false /*connectedOnly*/, false /*singlePort*/);
jiabinb76981e2023-01-18 00:58:30 +0000572 return !mmapOutMixPorts.empty() || !mmapInMixPorts.empty();
573}