blob: 6f89d4bc118c36dd9835220edb20a47682d8ed57 [file] [log] [blame]
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +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>
18#include <set>
19
20#define LOG_TAG "AHAL_Module"
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +000021#include <Utils.h>
22#include <aidl/android/media/audio/common/AudioInputFlags.h>
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +000023#include <aidl/android/media/audio/common/AudioOutputFlags.h>
Mikhail Naganov26dc9ad2023-06-23 13:55:37 -070024#include <android-base/logging.h>
25#include <android/binder_ibinder_platform.h>
26#include <error/expected_utils.h>
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +000027
Mikhail Naganov10c6fe22022-09-30 23:49:17 +000028#include "core-impl/Bluetooth.h"
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +000029#include "core-impl/Module.h"
jiabin253bd322023-01-25 23:57:31 +000030#include "core-impl/ModuleUsb.h"
Vlad Popa943b7e22022-12-08 14:24:12 +010031#include "core-impl/SoundDose.h"
Mikhail Naganovf429c032023-01-07 00:24:50 +000032#include "core-impl/StreamStub.h"
Mikhail Naganov3b125b72022-10-05 02:12:39 +000033#include "core-impl/Telephony.h"
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +000034#include "core-impl/utils.h"
35
Mikhail Naganov872d4a62023-03-09 18:19:01 -080036using aidl::android::hardware::audio::common::getFrameSizeInBytes;
37using aidl::android::hardware::audio::common::isBitPositionFlagSet;
38using aidl::android::hardware::audio::common::isValidAudioMode;
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +000039using aidl::android::hardware::audio::common::SinkMetadata;
40using aidl::android::hardware::audio::common::SourceMetadata;
Vlad Popa2afbd1e2022-12-28 17:04:58 +010041using aidl::android::hardware::audio::core::sounddose::ISoundDose;
Mikhail Naganov6a4872d2022-06-15 21:39:04 +000042using aidl::android::media::audio::common::AudioChannelLayout;
Mikhail Naganovef6bc742022-10-06 00:14:19 +000043using aidl::android::media::audio::common::AudioDevice;
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +000044using aidl::android::media::audio::common::AudioFormatDescription;
Mikhail Naganov6a4872d2022-06-15 21:39:04 +000045using aidl::android::media::audio::common::AudioFormatType;
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +000046using aidl::android::media::audio::common::AudioInputFlags;
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +000047using aidl::android::media::audio::common::AudioIoFlags;
jiabin9a8e6862023-01-12 23:06:37 +000048using aidl::android::media::audio::common::AudioMMapPolicy;
49using aidl::android::media::audio::common::AudioMMapPolicyInfo;
50using aidl::android::media::audio::common::AudioMMapPolicyType;
Mikhail Naganov04ae8222023-01-11 15:48:10 -080051using aidl::android::media::audio::common::AudioMode;
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +000052using aidl::android::media::audio::common::AudioOffloadInfo;
53using aidl::android::media::audio::common::AudioOutputFlags;
54using aidl::android::media::audio::common::AudioPort;
55using aidl::android::media::audio::common::AudioPortConfig;
56using aidl::android::media::audio::common::AudioPortExt;
57using aidl::android::media::audio::common::AudioProfile;
Mikhail Naganov20047bc2023-01-05 20:16:07 +000058using aidl::android::media::audio::common::Boolean;
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +000059using aidl::android::media::audio::common::Int;
Mikhail Naganov6725ef52023-02-09 17:52:50 -080060using aidl::android::media::audio::common::MicrophoneInfo;
Mikhail Naganov6a4872d2022-06-15 21:39:04 +000061using aidl::android::media::audio::common::PcmType;
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +000062
63namespace aidl::android::hardware::audio::core {
64
65namespace {
66
67bool generateDefaultPortConfig(const AudioPort& port, AudioPortConfig* config) {
68 *config = {};
69 config->portId = port.id;
70 if (port.profiles.empty()) {
71 LOG(ERROR) << __func__ << ": port " << port.id << " has no profiles";
72 return false;
73 }
74 const auto& profile = port.profiles.begin();
75 config->format = profile->format;
76 if (profile->channelMasks.empty()) {
77 LOG(ERROR) << __func__ << ": the first profile in port " << port.id
78 << " has no channel masks";
79 return false;
80 }
81 config->channelMask = *profile->channelMasks.begin();
82 if (profile->sampleRates.empty()) {
83 LOG(ERROR) << __func__ << ": the first profile in port " << port.id
84 << " has no sample rates";
85 return false;
86 }
87 Int sampleRate;
88 sampleRate.value = *profile->sampleRates.begin();
89 config->sampleRate = sampleRate;
90 config->flags = port.flags;
91 config->ext = port.ext;
92 return true;
93}
94
95bool findAudioProfile(const AudioPort& port, const AudioFormatDescription& format,
96 AudioProfile* profile) {
97 if (auto profilesIt =
98 find_if(port.profiles.begin(), port.profiles.end(),
99 [&format](const auto& profile) { return profile.format == format; });
100 profilesIt != port.profiles.end()) {
101 *profile = *profilesIt;
102 return true;
103 }
104 return false;
105}
Mikhail Naganov00603d12022-05-02 22:52:13 +0000106
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +0000107} // namespace
108
jiabin253bd322023-01-25 23:57:31 +0000109// static
110std::shared_ptr<Module> Module::createInstance(Type type) {
111 switch (type) {
112 case Module::Type::USB:
113 return ndk::SharedRefBase::make<ModuleUsb>(type);
114 case Type::DEFAULT:
115 case Type::R_SUBMIX:
116 default:
117 return ndk::SharedRefBase::make<Module>(type);
118 }
119}
120
Mikhail Naganovd5536d92023-03-24 18:27:58 -0700121std::ostream& operator<<(std::ostream& os, Module::Type t) {
122 switch (t) {
123 case Module::Type::DEFAULT:
124 os << "default";
125 break;
126 case Module::Type::R_SUBMIX:
127 os << "r_submix";
128 break;
129 case Module::Type::USB:
130 os << "usb";
131 break;
132 }
133 return os;
134}
135
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +0000136void Module::cleanUpPatch(int32_t patchId) {
137 erase_all_values(mPatches, std::set<int32_t>{patchId});
138}
139
Mikhail Naganov8651b362023-01-06 23:15:27 +0000140ndk::ScopedAStatus Module::createStreamContext(
141 int32_t in_portConfigId, int64_t in_bufferSizeFrames,
142 std::shared_ptr<IStreamCallback> asyncCallback,
143 std::shared_ptr<IStreamOutEventCallback> outEventCallback, StreamContext* out_context) {
Mikhail Naganov6a4872d2022-06-15 21:39:04 +0000144 if (in_bufferSizeFrames <= 0) {
145 LOG(ERROR) << __func__ << ": non-positive buffer size " << in_bufferSizeFrames;
146 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
147 }
148 if (in_bufferSizeFrames < kMinimumStreamBufferSizeFrames) {
149 LOG(ERROR) << __func__ << ": insufficient buffer size " << in_bufferSizeFrames
150 << ", must be at least " << kMinimumStreamBufferSizeFrames;
151 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
152 }
153 auto& configs = getConfig().portConfigs;
154 auto portConfigIt = findById<AudioPortConfig>(configs, in_portConfigId);
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000155 // Since this is a private method, it is assumed that
Mikhail Naganov6a4872d2022-06-15 21:39:04 +0000156 // validity of the portConfigId has already been checked.
157 const size_t frameSize =
158 getFrameSizeInBytes(portConfigIt->format.value(), portConfigIt->channelMask.value());
159 if (frameSize == 0) {
160 LOG(ERROR) << __func__ << ": could not calculate frame size for port config "
161 << portConfigIt->toString();
162 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
163 }
164 LOG(DEBUG) << __func__ << ": frame size " << frameSize << " bytes";
Mikhail Naganovb511b8a2023-05-15 14:35:24 -0700165 if (frameSize > static_cast<size_t>(kMaximumStreamBufferSizeBytes / in_bufferSizeFrames)) {
Mikhail Naganov6a4872d2022-06-15 21:39:04 +0000166 LOG(ERROR) << __func__ << ": buffer size " << in_bufferSizeFrames
167 << " frames is too large, maximum size is "
168 << kMaximumStreamBufferSizeBytes / frameSize;
169 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
170 }
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000171 const auto& flags = portConfigIt->flags.value();
172 if ((flags.getTag() == AudioIoFlags::Tag::input &&
Mikhail Naganova2c5ddf2022-09-12 22:57:14 +0000173 !isBitPositionFlagSet(flags.get<AudioIoFlags::Tag::input>(),
174 AudioInputFlags::MMAP_NOIRQ)) ||
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000175 (flags.getTag() == AudioIoFlags::Tag::output &&
Mikhail Naganova2c5ddf2022-09-12 22:57:14 +0000176 !isBitPositionFlagSet(flags.get<AudioIoFlags::Tag::output>(),
177 AudioOutputFlags::MMAP_NOIRQ))) {
Mikhail Naganov20047bc2023-01-05 20:16:07 +0000178 StreamContext::DebugParameters params{mDebug.streamTransientStateDelayMs,
Mikhail Naganov194daaa2023-01-05 22:34:20 +0000179 mVendorDebug.forceTransientBurst,
180 mVendorDebug.forceSynchronousDrain};
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000181 StreamContext temp(
182 std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
183 std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000184 portConfigIt->format.value(), portConfigIt->channelMask.value(),
Mikhail Naganovb42a69e2023-06-16 12:38:25 -0700185 portConfigIt->sampleRate.value().value, flags,
186 portConfigIt->ext.get<AudioPortExt::mix>().handle,
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000187 std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
Mikhail Naganov8651b362023-01-06 23:15:27 +0000188 asyncCallback, outEventCallback, params);
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000189 if (temp.isValid()) {
190 *out_context = std::move(temp);
191 } else {
192 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
193 }
194 } else {
195 // TODO: Implement simulation of MMAP buffer allocation
196 }
Mikhail Naganov6a4872d2022-06-15 21:39:04 +0000197 return ndk::ScopedAStatus::ok();
198}
199
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000200std::vector<AudioDevice> Module::findConnectedDevices(int32_t portConfigId) {
201 std::vector<AudioDevice> result;
202 auto& ports = getConfig().ports;
203 auto portIds = portIdsFromPortConfigIds(findConnectedPortConfigIds(portConfigId));
204 for (auto it = portIds.begin(); it != portIds.end(); ++it) {
205 auto portIt = findById<AudioPort>(ports, *it);
206 if (portIt != ports.end() && portIt->ext.getTag() == AudioPortExt::Tag::device) {
207 result.push_back(portIt->ext.template get<AudioPortExt::Tag::device>().device);
208 }
209 }
210 return result;
211}
212
213std::set<int32_t> Module::findConnectedPortConfigIds(int32_t portConfigId) {
214 std::set<int32_t> result;
215 auto patchIdsRange = mPatches.equal_range(portConfigId);
216 auto& patches = getConfig().patches;
217 for (auto it = patchIdsRange.first; it != patchIdsRange.second; ++it) {
218 auto patchIt = findById<AudioPatch>(patches, it->second);
219 if (patchIt == patches.end()) {
220 LOG(FATAL) << __func__ << ": patch with id " << it->second << " taken from mPatches "
221 << "not found in the configuration";
222 }
223 if (std::find(patchIt->sourcePortConfigIds.begin(), patchIt->sourcePortConfigIds.end(),
224 portConfigId) != patchIt->sourcePortConfigIds.end()) {
225 result.insert(patchIt->sinkPortConfigIds.begin(), patchIt->sinkPortConfigIds.end());
226 } else {
227 result.insert(patchIt->sourcePortConfigIds.begin(), patchIt->sourcePortConfigIds.end());
228 }
229 }
230 return result;
231}
232
Mikhail Naganov6a4872d2022-06-15 21:39:04 +0000233ndk::ScopedAStatus Module::findPortIdForNewStream(int32_t in_portConfigId, AudioPort** port) {
234 auto& configs = getConfig().portConfigs;
235 auto portConfigIt = findById<AudioPortConfig>(configs, in_portConfigId);
236 if (portConfigIt == configs.end()) {
237 LOG(ERROR) << __func__ << ": existing port config id " << in_portConfigId << " not found";
238 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
239 }
240 const int32_t portId = portConfigIt->portId;
241 // In our implementation, configs of mix ports always have unique IDs.
242 CHECK(portId != in_portConfigId);
243 auto& ports = getConfig().ports;
244 auto portIt = findById<AudioPort>(ports, portId);
245 if (portIt == ports.end()) {
246 LOG(ERROR) << __func__ << ": port id " << portId << " used by port config id "
247 << in_portConfigId << " not found";
248 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
249 }
250 if (mStreams.count(in_portConfigId) != 0) {
251 LOG(ERROR) << __func__ << ": port config id " << in_portConfigId
252 << " already has a stream opened on it";
253 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
254 }
255 if (portIt->ext.getTag() != AudioPortExt::Tag::mix) {
256 LOG(ERROR) << __func__ << ": port config id " << in_portConfigId
257 << " does not correspond to a mix port";
258 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
259 }
Mikhail Naganovb511b8a2023-05-15 14:35:24 -0700260 const size_t maxOpenStreamCount = portIt->ext.get<AudioPortExt::Tag::mix>().maxOpenStreamCount;
Mikhail Naganov6a4872d2022-06-15 21:39:04 +0000261 if (maxOpenStreamCount != 0 && mStreams.count(portId) >= maxOpenStreamCount) {
262 LOG(ERROR) << __func__ << ": port id " << portId
263 << " has already reached maximum allowed opened stream count: "
264 << maxOpenStreamCount;
265 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
266 }
267 *port = &(*portIt);
268 return ndk::ScopedAStatus::ok();
269}
270
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000271template <typename C>
272std::set<int32_t> Module::portIdsFromPortConfigIds(C portConfigIds) {
273 std::set<int32_t> result;
274 auto& portConfigs = getConfig().portConfigs;
275 for (auto it = portConfigIds.begin(); it != portConfigIds.end(); ++it) {
276 auto portConfigIt = findById<AudioPortConfig>(portConfigs, *it);
277 if (portConfigIt != portConfigs.end()) {
278 result.insert(portConfigIt->portId);
279 }
280 }
281 return result;
282}
283
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +0000284internal::Configuration& Module::getConfig() {
285 if (!mConfig) {
Mikhail Naganovc8e43122022-12-09 00:33:47 +0000286 switch (mType) {
287 case Type::DEFAULT:
288 mConfig = std::move(internal::getPrimaryConfiguration());
289 break;
290 case Type::R_SUBMIX:
291 mConfig = std::move(internal::getRSubmixConfiguration());
292 break;
jiabinb309d8d2023-01-20 19:07:15 +0000293 case Type::USB:
294 mConfig = std::move(internal::getUsbConfiguration());
jiabin253bd322023-01-25 23:57:31 +0000295 break;
Mikhail Naganovc8e43122022-12-09 00:33:47 +0000296 }
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +0000297 }
298 return *mConfig;
299}
300
301void Module::registerPatch(const AudioPatch& patch) {
302 auto& configs = getConfig().portConfigs;
303 auto do_insert = [&](const std::vector<int32_t>& portConfigIds) {
304 for (auto portConfigId : portConfigIds) {
305 auto configIt = findById<AudioPortConfig>(configs, portConfigId);
306 if (configIt != configs.end()) {
307 mPatches.insert(std::pair{portConfigId, patch.id});
308 if (configIt->portId != portConfigId) {
309 mPatches.insert(std::pair{configIt->portId, patch.id});
310 }
311 }
312 };
313 };
314 do_insert(patch.sourcePortConfigIds);
315 do_insert(patch.sinkPortConfigIds);
316}
317
Mikhail Naganov75b59df2023-06-23 13:39:40 -0700318ndk::ScopedAStatus Module::updateStreamsConnectedState(const AudioPatch& oldPatch,
319 const AudioPatch& newPatch) {
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000320 // Streams from the old patch need to be disconnected, streams from the new
321 // patch need to be connected. If the stream belongs to both patches, no need
322 // to update it.
Mikhail Naganov75b59df2023-06-23 13:39:40 -0700323 auto maybeFailure = ndk::ScopedAStatus::ok();
324 std::set<int32_t> idsToDisconnect, idsToConnect, idsToDisconnectOnFailure;
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000325 idsToDisconnect.insert(oldPatch.sourcePortConfigIds.begin(),
326 oldPatch.sourcePortConfigIds.end());
327 idsToDisconnect.insert(oldPatch.sinkPortConfigIds.begin(), oldPatch.sinkPortConfigIds.end());
328 idsToConnect.insert(newPatch.sourcePortConfigIds.begin(), newPatch.sourcePortConfigIds.end());
329 idsToConnect.insert(newPatch.sinkPortConfigIds.begin(), newPatch.sinkPortConfigIds.end());
330 std::for_each(idsToDisconnect.begin(), idsToDisconnect.end(), [&](const auto& portConfigId) {
Mikhail Naganov75b59df2023-06-23 13:39:40 -0700331 if (idsToConnect.count(portConfigId) == 0 && mStreams.count(portConfigId) != 0) {
332 if (auto status = mStreams.setStreamConnectedDevices(portConfigId, {}); status.isOk()) {
333 LOG(DEBUG) << "updateStreamsConnectedState: The stream on port config id "
334 << portConfigId << " has been disconnected";
335 } else {
336 // Disconnection is tricky to roll back, just register a failure.
337 maybeFailure = std::move(status);
338 }
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000339 }
340 });
Mikhail Naganov75b59df2023-06-23 13:39:40 -0700341 if (!maybeFailure.isOk()) return maybeFailure;
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000342 std::for_each(idsToConnect.begin(), idsToConnect.end(), [&](const auto& portConfigId) {
Mikhail Naganov75b59df2023-06-23 13:39:40 -0700343 if (idsToDisconnect.count(portConfigId) == 0 && mStreams.count(portConfigId) != 0) {
Mikhail Naganovef6bc742022-10-06 00:14:19 +0000344 const auto connectedDevices = findConnectedDevices(portConfigId);
Mikhail Naganov75b59df2023-06-23 13:39:40 -0700345 if (connectedDevices.empty()) {
346 // This is important as workers use the vector size to derive the connection status.
347 LOG(FATAL) << "updateStreamsConnectedState: No connected devices found for port "
348 "config id "
349 << portConfigId;
350 }
351 if (auto status = mStreams.setStreamConnectedDevices(portConfigId, connectedDevices);
352 status.isOk()) {
353 LOG(DEBUG) << "updateStreamsConnectedState: The stream on port config id "
354 << portConfigId << " has been connected to: "
355 << ::android::internal::ToString(connectedDevices);
356 } else {
357 maybeFailure = std::move(status);
358 idsToDisconnectOnFailure.insert(portConfigId);
359 }
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000360 }
361 });
Mikhail Naganov75b59df2023-06-23 13:39:40 -0700362 if (!maybeFailure.isOk()) {
363 LOG(WARNING) << __func__ << ": Due to a failure, disconnecting streams on port config ids "
364 << ::android::internal::ToString(idsToDisconnectOnFailure);
365 std::for_each(idsToDisconnectOnFailure.begin(), idsToDisconnectOnFailure.end(),
366 [&](const auto& portConfigId) {
367 auto status = mStreams.setStreamConnectedDevices(portConfigId, {});
368 (void)status.isOk(); // Can't do much about a failure here.
369 });
370 return maybeFailure;
371 }
372 return ndk::ScopedAStatus::ok();
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000373}
374
Mikhail Naganov00603d12022-05-02 22:52:13 +0000375ndk::ScopedAStatus Module::setModuleDebug(
376 const ::aidl::android::hardware::audio::core::ModuleDebug& in_debug) {
Mikhail Naganovd5536d92023-03-24 18:27:58 -0700377 LOG(DEBUG) << __func__ << ": " << mType << ": old flags:" << mDebug.toString()
Mikhail Naganov00603d12022-05-02 22:52:13 +0000378 << ", new flags: " << in_debug.toString();
379 if (mDebug.simulateDeviceConnections != in_debug.simulateDeviceConnections &&
380 !mConnectedDevicePorts.empty()) {
Mikhail Naganovd5536d92023-03-24 18:27:58 -0700381 LOG(ERROR) << __func__ << ": " << mType
382 << ": attempting to change device connections simulation while having external "
383 << "devices connected";
Mikhail Naganov00603d12022-05-02 22:52:13 +0000384 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
385 }
Mikhail Naganovbd483c02022-11-17 20:33:39 +0000386 if (in_debug.streamTransientStateDelayMs < 0) {
Mikhail Naganovd5536d92023-03-24 18:27:58 -0700387 LOG(ERROR) << __func__ << ": " << mType << ": streamTransientStateDelayMs is negative: "
Mikhail Naganovbd483c02022-11-17 20:33:39 +0000388 << in_debug.streamTransientStateDelayMs;
389 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
390 }
Mikhail Naganov00603d12022-05-02 22:52:13 +0000391 mDebug = in_debug;
392 return ndk::ScopedAStatus::ok();
393}
394
Mikhail Naganov3b125b72022-10-05 02:12:39 +0000395ndk::ScopedAStatus Module::getTelephony(std::shared_ptr<ITelephony>* _aidl_return) {
Mikhail Naganov7499a002023-02-27 18:51:44 -0800396 if (!mTelephony) {
Mikhail Naganov3b125b72022-10-05 02:12:39 +0000397 mTelephony = ndk::SharedRefBase::make<Telephony>();
398 }
Mikhail Naganov7499a002023-02-27 18:51:44 -0800399 *_aidl_return = mTelephony.getPtr();
Mikhail Naganov3b125b72022-10-05 02:12:39 +0000400 LOG(DEBUG) << __func__ << ": returning instance of ITelephony: " << _aidl_return->get();
401 return ndk::ScopedAStatus::ok();
402}
403
Mikhail Naganov10c6fe22022-09-30 23:49:17 +0000404ndk::ScopedAStatus Module::getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) {
Mikhail Naganov7499a002023-02-27 18:51:44 -0800405 if (!mBluetooth) {
Mikhail Naganov10c6fe22022-09-30 23:49:17 +0000406 mBluetooth = ndk::SharedRefBase::make<Bluetooth>();
Mikhail Naganov10c6fe22022-09-30 23:49:17 +0000407 }
Mikhail Naganov7499a002023-02-27 18:51:44 -0800408 *_aidl_return = mBluetooth.getPtr();
Mikhail Naganov10c6fe22022-09-30 23:49:17 +0000409 LOG(DEBUG) << __func__ << ": returning instance of IBluetooth: " << _aidl_return->get();
410 return ndk::ScopedAStatus::ok();
411}
412
Mikhail Naganov7499a002023-02-27 18:51:44 -0800413ndk::ScopedAStatus Module::getBluetoothA2dp(std::shared_ptr<IBluetoothA2dp>* _aidl_return) {
414 if (!mBluetoothA2dp) {
415 mBluetoothA2dp = ndk::SharedRefBase::make<BluetoothA2dp>();
416 }
417 *_aidl_return = mBluetoothA2dp.getPtr();
418 LOG(DEBUG) << __func__ << ": returning instance of IBluetoothA2dp: " << _aidl_return->get();
419 return ndk::ScopedAStatus::ok();
420}
421
Mikhail Naganovb5647da2023-03-06 14:37:38 -0800422ndk::ScopedAStatus Module::getBluetoothLe(std::shared_ptr<IBluetoothLe>* _aidl_return) {
423 if (!mBluetoothLe) {
424 mBluetoothLe = ndk::SharedRefBase::make<BluetoothLe>();
425 }
426 *_aidl_return = mBluetoothLe.getPtr();
427 LOG(DEBUG) << __func__ << ": returning instance of IBluetoothLe: " << _aidl_return->get();
428 return ndk::ScopedAStatus::ok();
429}
430
Mikhail Naganov00603d12022-05-02 22:52:13 +0000431ndk::ScopedAStatus Module::connectExternalDevice(const AudioPort& in_templateIdAndAdditionalData,
432 AudioPort* _aidl_return) {
433 const int32_t templateId = in_templateIdAndAdditionalData.id;
434 auto& ports = getConfig().ports;
435 AudioPort connectedPort;
436 { // Scope the template port so that we don't accidentally modify it.
437 auto templateIt = findById<AudioPort>(ports, templateId);
438 if (templateIt == ports.end()) {
439 LOG(ERROR) << __func__ << ": port id " << templateId << " not found";
440 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
441 }
442 if (templateIt->ext.getTag() != AudioPortExt::Tag::device) {
443 LOG(ERROR) << __func__ << ": port id " << templateId << " is not a device port";
444 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
445 }
446 if (!templateIt->profiles.empty()) {
447 LOG(ERROR) << __func__ << ": port id " << templateId
448 << " does not have dynamic profiles";
449 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
450 }
451 auto& templateDevicePort = templateIt->ext.get<AudioPortExt::Tag::device>();
452 if (templateDevicePort.device.type.connection.empty()) {
453 LOG(ERROR) << __func__ << ": port id " << templateId << " is permanently attached";
454 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
455 }
456 // Postpone id allocation until we ensure that there are no client errors.
457 connectedPort = *templateIt;
458 connectedPort.extraAudioDescriptors = in_templateIdAndAdditionalData.extraAudioDescriptors;
459 const auto& inputDevicePort =
460 in_templateIdAndAdditionalData.ext.get<AudioPortExt::Tag::device>();
461 auto& connectedDevicePort = connectedPort.ext.get<AudioPortExt::Tag::device>();
462 connectedDevicePort.device.address = inputDevicePort.device.address;
463 LOG(DEBUG) << __func__ << ": device port " << connectedPort.id << " device set to "
464 << connectedDevicePort.device.toString();
465 // Check if there is already a connected port with for the same external device.
Mikhail Naganov7b2d12b2023-03-24 18:29:14 -0700466 for (auto connectedPortPair : mConnectedDevicePorts) {
467 auto connectedPortIt = findById<AudioPort>(ports, connectedPortPair.first);
Mikhail Naganov00603d12022-05-02 22:52:13 +0000468 if (connectedPortIt->ext.get<AudioPortExt::Tag::device>().device ==
469 connectedDevicePort.device) {
470 LOG(ERROR) << __func__ << ": device " << connectedDevicePort.device.toString()
Mikhail Naganov7b2d12b2023-03-24 18:29:14 -0700471 << " is already connected at the device port id "
472 << connectedPortPair.first;
Mikhail Naganov00603d12022-05-02 22:52:13 +0000473 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
474 }
475 }
476 }
477
478 if (!mDebug.simulateDeviceConnections) {
Mikhail Naganov26dc9ad2023-06-23 13:55:37 -0700479 RETURN_STATUS_IF_ERROR(populateConnectedDevicePort(&connectedPort));
Mikhail Naganov7b2d12b2023-03-24 18:29:14 -0700480 } else {
481 auto& connectedProfiles = getConfig().connectedProfiles;
482 if (auto connectedProfilesIt = connectedProfiles.find(templateId);
483 connectedProfilesIt != connectedProfiles.end()) {
484 connectedPort.profiles = connectedProfilesIt->second;
485 }
486 }
487 if (connectedPort.profiles.empty()) {
488 LOG(ERROR) << "Profiles of a connected port still empty after connecting external device "
489 << connectedPort.toString();
Mikhail Naganov00603d12022-05-02 22:52:13 +0000490 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
491 }
492
493 connectedPort.id = ++getConfig().nextPortId;
Mikhail Naganov7b2d12b2023-03-24 18:29:14 -0700494 auto [connectedPortsIt, _] =
495 mConnectedDevicePorts.insert(std::pair(connectedPort.id, std::vector<int32_t>()));
Mikhail Naganov00603d12022-05-02 22:52:13 +0000496 LOG(DEBUG) << __func__ << ": template port " << templateId << " external device connected, "
497 << "connected port ID " << connectedPort.id;
Mikhail Naganov00603d12022-05-02 22:52:13 +0000498 ports.push_back(connectedPort);
jiabin783c48b2023-02-28 18:28:06 +0000499 onExternalDeviceConnectionChanged(connectedPort, true /*connected*/);
Mikhail Naganov00603d12022-05-02 22:52:13 +0000500
Mikhail Naganov7b2d12b2023-03-24 18:29:14 -0700501 std::vector<int32_t> routablePortIds;
Mikhail Naganov00603d12022-05-02 22:52:13 +0000502 std::vector<AudioRoute> newRoutes;
503 auto& routes = getConfig().routes;
504 for (auto& r : routes) {
505 if (r.sinkPortId == templateId) {
506 AudioRoute newRoute;
507 newRoute.sourcePortIds = r.sourcePortIds;
508 newRoute.sinkPortId = connectedPort.id;
509 newRoute.isExclusive = r.isExclusive;
510 newRoutes.push_back(std::move(newRoute));
Mikhail Naganov7b2d12b2023-03-24 18:29:14 -0700511 routablePortIds.insert(routablePortIds.end(), r.sourcePortIds.begin(),
512 r.sourcePortIds.end());
Mikhail Naganov00603d12022-05-02 22:52:13 +0000513 } else {
514 auto& srcs = r.sourcePortIds;
515 if (std::find(srcs.begin(), srcs.end(), templateId) != srcs.end()) {
516 srcs.push_back(connectedPort.id);
Mikhail Naganov7b2d12b2023-03-24 18:29:14 -0700517 routablePortIds.push_back(r.sinkPortId);
Mikhail Naganov00603d12022-05-02 22:52:13 +0000518 }
519 }
520 }
521 routes.insert(routes.end(), newRoutes.begin(), newRoutes.end());
522
Mikhail Naganov7b2d12b2023-03-24 18:29:14 -0700523 // Note: this is a simplistic approach assuming that a mix port can only be populated
524 // from a single device port. Implementing support for stuffing dynamic profiles with a superset
525 // of all profiles from all routable dynamic device ports would be more involved.
526 for (const auto mixPortId : routablePortIds) {
527 auto portsIt = findById<AudioPort>(ports, mixPortId);
528 if (portsIt != ports.end() && portsIt->profiles.empty()) {
529 portsIt->profiles = connectedPort.profiles;
530 connectedPortsIt->second.push_back(portsIt->id);
531 }
532 }
533 *_aidl_return = std::move(connectedPort);
534
Mikhail Naganov00603d12022-05-02 22:52:13 +0000535 return ndk::ScopedAStatus::ok();
536}
537
538ndk::ScopedAStatus Module::disconnectExternalDevice(int32_t in_portId) {
539 auto& ports = getConfig().ports;
540 auto portIt = findById<AudioPort>(ports, in_portId);
541 if (portIt == ports.end()) {
542 LOG(ERROR) << __func__ << ": port id " << in_portId << " not found";
543 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
544 }
545 if (portIt->ext.getTag() != AudioPortExt::Tag::device) {
546 LOG(ERROR) << __func__ << ": port id " << in_portId << " is not a device port";
547 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
548 }
Mikhail Naganov7b2d12b2023-03-24 18:29:14 -0700549 auto connectedPortsIt = mConnectedDevicePorts.find(in_portId);
550 if (connectedPortsIt == mConnectedDevicePorts.end()) {
Mikhail Naganov00603d12022-05-02 22:52:13 +0000551 LOG(ERROR) << __func__ << ": port id " << in_portId << " is not a connected device port";
552 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
553 }
554 auto& configs = getConfig().portConfigs;
555 auto& initials = getConfig().initialConfigs;
556 auto configIt = std::find_if(configs.begin(), configs.end(), [&](const auto& config) {
557 if (config.portId == in_portId) {
558 // Check if the configuration was provided by the client.
559 const auto& initialIt = findById<AudioPortConfig>(initials, config.id);
560 return initialIt == initials.end() || config != *initialIt;
561 }
562 return false;
563 });
564 if (configIt != configs.end()) {
565 LOG(ERROR) << __func__ << ": port id " << in_portId << " has a non-default config with id "
566 << configIt->id;
567 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
568 }
jiabin783c48b2023-02-28 18:28:06 +0000569 onExternalDeviceConnectionChanged(*portIt, false /*connected*/);
Mikhail Naganov00603d12022-05-02 22:52:13 +0000570 ports.erase(portIt);
Mikhail Naganov00603d12022-05-02 22:52:13 +0000571 LOG(DEBUG) << __func__ << ": connected device port " << in_portId << " released";
572
573 auto& routes = getConfig().routes;
574 for (auto routesIt = routes.begin(); routesIt != routes.end();) {
575 if (routesIt->sinkPortId == in_portId) {
576 routesIt = routes.erase(routesIt);
577 } else {
578 // Note: the list of sourcePortIds can't become empty because there must
579 // be the id of the template port in the route.
580 erase_if(routesIt->sourcePortIds, [in_portId](auto src) { return src == in_portId; });
581 ++routesIt;
582 }
583 }
584
Mikhail Naganov7b2d12b2023-03-24 18:29:14 -0700585 for (const auto mixPortId : connectedPortsIt->second) {
586 auto mixPortIt = findById<AudioPort>(ports, mixPortId);
587 if (mixPortIt != ports.end()) {
588 mixPortIt->profiles = {};
589 }
590 }
591 mConnectedDevicePorts.erase(connectedPortsIt);
592
Mikhail Naganov00603d12022-05-02 22:52:13 +0000593 return ndk::ScopedAStatus::ok();
594}
595
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +0000596ndk::ScopedAStatus Module::getAudioPatches(std::vector<AudioPatch>* _aidl_return) {
597 *_aidl_return = getConfig().patches;
598 LOG(DEBUG) << __func__ << ": returning " << _aidl_return->size() << " patches";
599 return ndk::ScopedAStatus::ok();
600}
601
602ndk::ScopedAStatus Module::getAudioPort(int32_t in_portId, AudioPort* _aidl_return) {
603 auto& ports = getConfig().ports;
604 auto portIt = findById<AudioPort>(ports, in_portId);
605 if (portIt != ports.end()) {
606 *_aidl_return = *portIt;
607 LOG(DEBUG) << __func__ << ": returning port by id " << in_portId;
608 return ndk::ScopedAStatus::ok();
609 }
610 LOG(ERROR) << __func__ << ": port id " << in_portId << " not found";
611 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
612}
613
614ndk::ScopedAStatus Module::getAudioPortConfigs(std::vector<AudioPortConfig>* _aidl_return) {
615 *_aidl_return = getConfig().portConfigs;
616 LOG(DEBUG) << __func__ << ": returning " << _aidl_return->size() << " port configs";
617 return ndk::ScopedAStatus::ok();
618}
619
620ndk::ScopedAStatus Module::getAudioPorts(std::vector<AudioPort>* _aidl_return) {
621 *_aidl_return = getConfig().ports;
622 LOG(DEBUG) << __func__ << ": returning " << _aidl_return->size() << " ports";
623 return ndk::ScopedAStatus::ok();
624}
625
626ndk::ScopedAStatus Module::getAudioRoutes(std::vector<AudioRoute>* _aidl_return) {
627 *_aidl_return = getConfig().routes;
628 LOG(DEBUG) << __func__ << ": returning " << _aidl_return->size() << " routes";
629 return ndk::ScopedAStatus::ok();
630}
631
Mikhail Naganov00603d12022-05-02 22:52:13 +0000632ndk::ScopedAStatus Module::getAudioRoutesForAudioPort(int32_t in_portId,
633 std::vector<AudioRoute>* _aidl_return) {
634 auto& ports = getConfig().ports;
635 if (auto portIt = findById<AudioPort>(ports, in_portId); portIt == ports.end()) {
636 LOG(ERROR) << __func__ << ": port id " << in_portId << " not found";
637 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
638 }
639 auto& routes = getConfig().routes;
640 std::copy_if(routes.begin(), routes.end(), std::back_inserter(*_aidl_return),
641 [&](const auto& r) {
642 const auto& srcs = r.sourcePortIds;
643 return r.sinkPortId == in_portId ||
644 std::find(srcs.begin(), srcs.end(), in_portId) != srcs.end();
645 });
646 return ndk::ScopedAStatus::ok();
647}
648
Mikhail Naganov6a4872d2022-06-15 21:39:04 +0000649ndk::ScopedAStatus Module::openInputStream(const OpenInputStreamArguments& in_args,
650 OpenInputStreamReturn* _aidl_return) {
651 LOG(DEBUG) << __func__ << ": port config id " << in_args.portConfigId << ", buffer size "
652 << in_args.bufferSizeFrames << " frames";
653 AudioPort* port = nullptr;
Mikhail Naganov26dc9ad2023-06-23 13:55:37 -0700654 RETURN_STATUS_IF_ERROR(findPortIdForNewStream(in_args.portConfigId, &port));
Mikhail Naganov6a4872d2022-06-15 21:39:04 +0000655 if (port->flags.getTag() != AudioIoFlags::Tag::input) {
656 LOG(ERROR) << __func__ << ": port config id " << in_args.portConfigId
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +0000657 << " does not correspond to an input mix port";
658 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
659 }
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000660 StreamContext context;
Mikhail Naganov26dc9ad2023-06-23 13:55:37 -0700661 RETURN_STATUS_IF_ERROR(createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames,
662 nullptr, nullptr, &context));
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000663 context.fillDescriptor(&_aidl_return->desc);
Mikhail Naganove9f10fc2022-10-14 23:31:52 +0000664 std::shared_ptr<StreamIn> stream;
Mikhail Naganov9d16a6a2023-06-26 17:21:04 -0700665 RETURN_STATUS_IF_ERROR(createInputStream(in_args.sinkMetadata, std::move(context),
666 mConfig->microphones, &stream));
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000667 StreamWrapper streamWrapper(stream);
Mikhail Naganov75b59df2023-06-23 13:39:40 -0700668 if (auto patchIt = mPatches.find(in_args.portConfigId); patchIt != mPatches.end()) {
669 RETURN_STATUS_IF_ERROR(
670 streamWrapper.setConnectedDevices(findConnectedDevices(in_args.portConfigId)));
671 }
Mikhail Naganovdf5feba2022-12-15 00:11:14 +0000672 AIBinder_setMinSchedulerPolicy(streamWrapper.getBinder().get(), SCHED_NORMAL,
673 ANDROID_PRIORITY_AUDIO);
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000674 mStreams.insert(port->id, in_args.portConfigId, std::move(streamWrapper));
Mikhail Naganov6a4872d2022-06-15 21:39:04 +0000675 _aidl_return->stream = std::move(stream);
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +0000676 return ndk::ScopedAStatus::ok();
677}
678
Mikhail Naganov6a4872d2022-06-15 21:39:04 +0000679ndk::ScopedAStatus Module::openOutputStream(const OpenOutputStreamArguments& in_args,
680 OpenOutputStreamReturn* _aidl_return) {
681 LOG(DEBUG) << __func__ << ": port config id " << in_args.portConfigId << ", has offload info? "
682 << (in_args.offloadInfo.has_value()) << ", buffer size " << in_args.bufferSizeFrames
683 << " frames";
684 AudioPort* port = nullptr;
Mikhail Naganov26dc9ad2023-06-23 13:55:37 -0700685 RETURN_STATUS_IF_ERROR(findPortIdForNewStream(in_args.portConfigId, &port));
Mikhail Naganov6a4872d2022-06-15 21:39:04 +0000686 if (port->flags.getTag() != AudioIoFlags::Tag::output) {
687 LOG(ERROR) << __func__ << ": port config id " << in_args.portConfigId
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +0000688 << " does not correspond to an output mix port";
689 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
690 }
Mikhail Naganova2c5ddf2022-09-12 22:57:14 +0000691 const bool isOffload = isBitPositionFlagSet(port->flags.get<AudioIoFlags::Tag::output>(),
692 AudioOutputFlags::COMPRESS_OFFLOAD);
693 if (isOffload && !in_args.offloadInfo.has_value()) {
Mikhail Naganov6a4872d2022-06-15 21:39:04 +0000694 LOG(ERROR) << __func__ << ": port id " << port->id
Mikhail Naganov111e0ce2022-06-17 21:41:19 +0000695 << " has COMPRESS_OFFLOAD flag set, requires offload info";
696 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
697 }
Mikhail Naganov30301a42022-09-13 01:20:45 +0000698 const bool isNonBlocking = isBitPositionFlagSet(port->flags.get<AudioIoFlags::Tag::output>(),
699 AudioOutputFlags::NON_BLOCKING);
700 if (isNonBlocking && in_args.callback == nullptr) {
701 LOG(ERROR) << __func__ << ": port id " << port->id
702 << " has NON_BLOCKING flag set, requires async callback";
703 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
704 }
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000705 StreamContext context;
Mikhail Naganov26dc9ad2023-06-23 13:55:37 -0700706 RETURN_STATUS_IF_ERROR(createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames,
707 isNonBlocking ? in_args.callback : nullptr,
708 in_args.eventCallback, &context));
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000709 context.fillDescriptor(&_aidl_return->desc);
Mikhail Naganove9f10fc2022-10-14 23:31:52 +0000710 std::shared_ptr<StreamOut> stream;
Mikhail Naganov9d16a6a2023-06-26 17:21:04 -0700711 RETURN_STATUS_IF_ERROR(createOutputStream(in_args.sourceMetadata, std::move(context),
712 in_args.offloadInfo, &stream));
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000713 StreamWrapper streamWrapper(stream);
Mikhail Naganov75b59df2023-06-23 13:39:40 -0700714 if (auto patchIt = mPatches.find(in_args.portConfigId); patchIt != mPatches.end()) {
715 RETURN_STATUS_IF_ERROR(
716 streamWrapper.setConnectedDevices(findConnectedDevices(in_args.portConfigId)));
717 }
Mikhail Naganovdf5feba2022-12-15 00:11:14 +0000718 AIBinder_setMinSchedulerPolicy(streamWrapper.getBinder().get(), SCHED_NORMAL,
719 ANDROID_PRIORITY_AUDIO);
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000720 mStreams.insert(port->id, in_args.portConfigId, std::move(streamWrapper));
Mikhail Naganov6a4872d2022-06-15 21:39:04 +0000721 _aidl_return->stream = std::move(stream);
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +0000722 return ndk::ScopedAStatus::ok();
723}
724
Mikhail Naganov74927202022-12-19 16:37:14 +0000725ndk::ScopedAStatus Module::getSupportedPlaybackRateFactors(
726 SupportedPlaybackRateFactors* _aidl_return) {
727 LOG(DEBUG) << __func__;
728 (void)_aidl_return;
729 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
730}
731
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +0000732ndk::ScopedAStatus Module::setAudioPatch(const AudioPatch& in_requested, AudioPatch* _aidl_return) {
Mikhail Naganov16db9b72022-06-17 21:36:18 +0000733 LOG(DEBUG) << __func__ << ": requested patch " << in_requested.toString();
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +0000734 if (in_requested.sourcePortConfigIds.empty()) {
735 LOG(ERROR) << __func__ << ": requested patch has empty sources list";
736 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
737 }
738 if (!all_unique<int32_t>(in_requested.sourcePortConfigIds)) {
739 LOG(ERROR) << __func__ << ": requested patch has duplicate ids in the sources list";
740 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
741 }
742 if (in_requested.sinkPortConfigIds.empty()) {
743 LOG(ERROR) << __func__ << ": requested patch has empty sinks list";
744 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
745 }
746 if (!all_unique<int32_t>(in_requested.sinkPortConfigIds)) {
747 LOG(ERROR) << __func__ << ": requested patch has duplicate ids in the sinks list";
748 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
749 }
750
751 auto& configs = getConfig().portConfigs;
752 std::vector<int32_t> missingIds;
753 auto sources =
754 selectByIds<AudioPortConfig>(configs, in_requested.sourcePortConfigIds, &missingIds);
755 if (!missingIds.empty()) {
756 LOG(ERROR) << __func__ << ": following source port config ids not found: "
757 << ::android::internal::ToString(missingIds);
758 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
759 }
760 auto sinks = selectByIds<AudioPortConfig>(configs, in_requested.sinkPortConfigIds, &missingIds);
761 if (!missingIds.empty()) {
762 LOG(ERROR) << __func__ << ": following sink port config ids not found: "
763 << ::android::internal::ToString(missingIds);
764 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
765 }
766 // bool indicates whether a non-exclusive route is available.
767 // If only an exclusive route is available, that means the patch can not be
768 // established if there is any other patch which currently uses the sink port.
769 std::map<int32_t, bool> allowedSinkPorts;
770 auto& routes = getConfig().routes;
771 for (auto src : sources) {
772 for (const auto& r : routes) {
773 const auto& srcs = r.sourcePortIds;
774 if (std::find(srcs.begin(), srcs.end(), src->portId) != srcs.end()) {
775 if (!allowedSinkPorts[r.sinkPortId]) { // prefer non-exclusive
776 allowedSinkPorts[r.sinkPortId] = !r.isExclusive;
777 }
778 }
779 }
780 }
781 for (auto sink : sinks) {
782 if (allowedSinkPorts.count(sink->portId) == 0) {
783 LOG(ERROR) << __func__ << ": there is no route to the sink port id " << sink->portId;
784 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
785 }
786 }
Mikhail Naganov26dc9ad2023-06-23 13:55:37 -0700787 RETURN_STATUS_IF_ERROR(checkAudioPatchEndpointsMatch(sources, sinks));
jiabin253bd322023-01-25 23:57:31 +0000788
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +0000789 auto& patches = getConfig().patches;
790 auto existing = patches.end();
791 std::optional<decltype(mPatches)> patchesBackup;
792 if (in_requested.id != 0) {
793 existing = findById<AudioPatch>(patches, in_requested.id);
794 if (existing != patches.end()) {
795 patchesBackup = mPatches;
796 cleanUpPatch(existing->id);
797 } else {
798 LOG(ERROR) << __func__ << ": not found existing patch id " << in_requested.id;
799 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
800 }
801 }
802 // Validate the requested patch.
803 for (const auto& [sinkPortId, nonExclusive] : allowedSinkPorts) {
804 if (!nonExclusive && mPatches.count(sinkPortId) != 0) {
805 LOG(ERROR) << __func__ << ": sink port id " << sinkPortId
806 << "is exclusive and is already used by some other patch";
807 if (patchesBackup.has_value()) {
808 mPatches = std::move(*patchesBackup);
809 }
810 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
811 }
812 }
813 *_aidl_return = in_requested;
Mikhail Naganov6a4872d2022-06-15 21:39:04 +0000814 _aidl_return->minimumStreamBufferSizeFrames = kMinimumStreamBufferSizeFrames;
815 _aidl_return->latenciesMs.clear();
816 _aidl_return->latenciesMs.insert(_aidl_return->latenciesMs.end(),
817 _aidl_return->sinkPortConfigIds.size(), kLatencyMs);
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000818 AudioPatch oldPatch{};
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +0000819 if (existing == patches.end()) {
820 _aidl_return->id = getConfig().nextPatchId++;
821 patches.push_back(*_aidl_return);
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +0000822 } else {
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000823 oldPatch = *existing;
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +0000824 }
Mikhail Naganov75b59df2023-06-23 13:39:40 -0700825 patchesBackup = mPatches;
826 registerPatch(*_aidl_return);
827 if (auto status = updateStreamsConnectedState(oldPatch, *_aidl_return); !status.isOk()) {
828 mPatches = std::move(*patchesBackup);
829 if (existing == patches.end()) {
830 patches.pop_back();
831 } else {
832 *existing = oldPatch;
833 }
834 return status;
835 }
Mikhail Naganov4f5d3f12022-07-22 23:23:25 +0000836
837 LOG(DEBUG) << __func__ << ": " << (oldPatch.id == 0 ? "created" : "updated") << " patch "
838 << _aidl_return->toString();
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +0000839 return ndk::ScopedAStatus::ok();
840}
841
842ndk::ScopedAStatus Module::setAudioPortConfig(const AudioPortConfig& in_requested,
843 AudioPortConfig* out_suggested, bool* _aidl_return) {
844 LOG(DEBUG) << __func__ << ": requested " << in_requested.toString();
845 auto& configs = getConfig().portConfigs;
846 auto existing = configs.end();
847 if (in_requested.id != 0) {
848 if (existing = findById<AudioPortConfig>(configs, in_requested.id);
849 existing == configs.end()) {
850 LOG(ERROR) << __func__ << ": existing port config id " << in_requested.id
851 << " not found";
852 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
853 }
854 }
855
856 const int portId = existing != configs.end() ? existing->portId : in_requested.portId;
857 if (portId == 0) {
858 LOG(ERROR) << __func__ << ": input port config does not specify portId";
859 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
860 }
861 auto& ports = getConfig().ports;
862 auto portIt = findById<AudioPort>(ports, portId);
863 if (portIt == ports.end()) {
864 LOG(ERROR) << __func__ << ": input port config points to non-existent portId " << portId;
865 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
866 }
867 if (existing != configs.end()) {
868 *out_suggested = *existing;
869 } else {
870 AudioPortConfig newConfig;
871 if (generateDefaultPortConfig(*portIt, &newConfig)) {
872 *out_suggested = newConfig;
873 } else {
874 LOG(ERROR) << __func__ << ": unable generate a default config for port " << portId;
875 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
876 }
877 }
878 // From this moment, 'out_suggested' is either an existing port config,
879 // or a new generated config. Now attempt to update it according to the specified
880 // fields of 'in_requested'.
881
882 bool requestedIsValid = true, requestedIsFullySpecified = true;
883
884 AudioIoFlags portFlags = portIt->flags;
885 if (in_requested.flags.has_value()) {
886 if (in_requested.flags.value() != portFlags) {
887 LOG(WARNING) << __func__ << ": requested flags "
888 << in_requested.flags.value().toString() << " do not match port's "
889 << portId << " flags " << portFlags.toString();
890 requestedIsValid = false;
891 }
892 } else {
893 requestedIsFullySpecified = false;
894 }
895
896 AudioProfile portProfile;
897 if (in_requested.format.has_value()) {
898 const auto& format = in_requested.format.value();
899 if (findAudioProfile(*portIt, format, &portProfile)) {
900 out_suggested->format = format;
901 } else {
902 LOG(WARNING) << __func__ << ": requested format " << format.toString()
903 << " is not found in port's " << portId << " profiles";
904 requestedIsValid = false;
905 }
906 } else {
907 requestedIsFullySpecified = false;
908 }
909 if (!findAudioProfile(*portIt, out_suggested->format.value(), &portProfile)) {
910 LOG(ERROR) << __func__ << ": port " << portId << " does not support format "
911 << out_suggested->format.value().toString() << " anymore";
912 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
913 }
914
915 if (in_requested.channelMask.has_value()) {
916 const auto& channelMask = in_requested.channelMask.value();
917 if (find(portProfile.channelMasks.begin(), portProfile.channelMasks.end(), channelMask) !=
918 portProfile.channelMasks.end()) {
919 out_suggested->channelMask = channelMask;
920 } else {
921 LOG(WARNING) << __func__ << ": requested channel mask " << channelMask.toString()
922 << " is not supported for the format " << portProfile.format.toString()
923 << " by the port " << portId;
924 requestedIsValid = false;
925 }
926 } else {
927 requestedIsFullySpecified = false;
928 }
929
930 if (in_requested.sampleRate.has_value()) {
931 const auto& sampleRate = in_requested.sampleRate.value();
932 if (find(portProfile.sampleRates.begin(), portProfile.sampleRates.end(),
933 sampleRate.value) != portProfile.sampleRates.end()) {
934 out_suggested->sampleRate = sampleRate;
935 } else {
936 LOG(WARNING) << __func__ << ": requested sample rate " << sampleRate.value
937 << " is not supported for the format " << portProfile.format.toString()
938 << " by the port " << portId;
939 requestedIsValid = false;
940 }
941 } else {
942 requestedIsFullySpecified = false;
943 }
944
945 if (in_requested.gain.has_value()) {
946 // Let's pretend that gain can always be applied.
947 out_suggested->gain = in_requested.gain.value();
948 }
949
Mikhail Naganov248e9502023-02-21 16:32:40 -0800950 if (in_requested.ext.getTag() != AudioPortExt::Tag::unspecified) {
951 if (in_requested.ext.getTag() == out_suggested->ext.getTag()) {
952 if (out_suggested->ext.getTag() == AudioPortExt::Tag::mix) {
953 // 'AudioMixPortExt.handle' is set by the client, copy from in_requested
954 out_suggested->ext.get<AudioPortExt::Tag::mix>().handle =
955 in_requested.ext.get<AudioPortExt::Tag::mix>().handle;
956 }
957 } else {
958 LOG(WARNING) << __func__ << ": requested ext tag "
959 << toString(in_requested.ext.getTag()) << " do not match port's tag "
960 << toString(out_suggested->ext.getTag());
961 requestedIsValid = false;
962 }
963 }
964
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +0000965 if (existing == configs.end() && requestedIsValid && requestedIsFullySpecified) {
966 out_suggested->id = getConfig().nextPortId++;
967 configs.push_back(*out_suggested);
968 *_aidl_return = true;
969 LOG(DEBUG) << __func__ << ": created new port config " << out_suggested->toString();
970 } else if (existing != configs.end() && requestedIsValid) {
971 *existing = *out_suggested;
972 *_aidl_return = true;
973 LOG(DEBUG) << __func__ << ": updated port config " << out_suggested->toString();
974 } else {
975 LOG(DEBUG) << __func__ << ": not applied; existing config ? " << (existing != configs.end())
976 << "; requested is valid? " << requestedIsValid << ", fully specified? "
977 << requestedIsFullySpecified;
978 *_aidl_return = false;
979 }
980 return ndk::ScopedAStatus::ok();
981}
982
983ndk::ScopedAStatus Module::resetAudioPatch(int32_t in_patchId) {
984 auto& patches = getConfig().patches;
985 auto patchIt = findById<AudioPatch>(patches, in_patchId);
986 if (patchIt != patches.end()) {
Mikhail Naganov75b59df2023-06-23 13:39:40 -0700987 auto patchesBackup = mPatches;
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +0000988 cleanUpPatch(patchIt->id);
Mikhail Naganov75b59df2023-06-23 13:39:40 -0700989 if (auto status = updateStreamsConnectedState(*patchIt, AudioPatch{}); !status.isOk()) {
990 mPatches = std::move(patchesBackup);
991 return status;
992 }
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +0000993 patches.erase(patchIt);
994 LOG(DEBUG) << __func__ << ": erased patch " << in_patchId;
995 return ndk::ScopedAStatus::ok();
996 }
997 LOG(ERROR) << __func__ << ": patch id " << in_patchId << " not found";
998 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
999}
1000
1001ndk::ScopedAStatus Module::resetAudioPortConfig(int32_t in_portConfigId) {
1002 auto& configs = getConfig().portConfigs;
1003 auto configIt = findById<AudioPortConfig>(configs, in_portConfigId);
1004 if (configIt != configs.end()) {
1005 if (mStreams.count(in_portConfigId) != 0) {
1006 LOG(ERROR) << __func__ << ": port config id " << in_portConfigId
1007 << " has a stream opened on it";
1008 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
1009 }
1010 auto patchIt = mPatches.find(in_portConfigId);
1011 if (patchIt != mPatches.end()) {
1012 LOG(ERROR) << __func__ << ": port config id " << in_portConfigId
1013 << " is used by the patch with id " << patchIt->second;
1014 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
1015 }
1016 auto& initials = getConfig().initialConfigs;
1017 auto initialIt = findById<AudioPortConfig>(initials, in_portConfigId);
1018 if (initialIt == initials.end()) {
1019 configs.erase(configIt);
1020 LOG(DEBUG) << __func__ << ": erased port config " << in_portConfigId;
1021 } else if (*configIt != *initialIt) {
1022 *configIt = *initialIt;
1023 LOG(DEBUG) << __func__ << ": reset port config " << in_portConfigId;
1024 }
1025 return ndk::ScopedAStatus::ok();
1026 }
1027 LOG(ERROR) << __func__ << ": port config id " << in_portConfigId << " not found";
1028 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
1029}
1030
Mikhail Naganov3b125b72022-10-05 02:12:39 +00001031ndk::ScopedAStatus Module::getMasterMute(bool* _aidl_return) {
1032 *_aidl_return = mMasterMute;
1033 LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
1034 return ndk::ScopedAStatus::ok();
1035}
1036
1037ndk::ScopedAStatus Module::setMasterMute(bool in_mute) {
1038 LOG(DEBUG) << __func__ << ": " << in_mute;
jiabin783c48b2023-02-28 18:28:06 +00001039 auto result = mDebug.simulateDeviceConnections ? ndk::ScopedAStatus::ok()
1040 : onMasterMuteChanged(in_mute);
1041 if (result.isOk()) {
1042 mMasterMute = in_mute;
1043 } else {
1044 LOG(ERROR) << __func__ << ": failed calling onMasterMuteChanged(" << in_mute
1045 << "), error=" << result;
1046 // Reset master mute if it failed.
1047 onMasterMuteChanged(mMasterMute);
1048 }
1049 return std::move(result);
Mikhail Naganov3b125b72022-10-05 02:12:39 +00001050}
1051
1052ndk::ScopedAStatus Module::getMasterVolume(float* _aidl_return) {
1053 *_aidl_return = mMasterVolume;
1054 LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
1055 return ndk::ScopedAStatus::ok();
1056}
1057
1058ndk::ScopedAStatus Module::setMasterVolume(float in_volume) {
1059 LOG(DEBUG) << __func__ << ": " << in_volume;
1060 if (in_volume >= 0.0f && in_volume <= 1.0f) {
jiabin783c48b2023-02-28 18:28:06 +00001061 auto result = mDebug.simulateDeviceConnections ? ndk::ScopedAStatus::ok()
1062 : onMasterVolumeChanged(in_volume);
1063 if (result.isOk()) {
1064 mMasterVolume = in_volume;
1065 } else {
1066 // Reset master volume if it failed.
1067 LOG(ERROR) << __func__ << ": failed calling onMasterVolumeChanged(" << in_volume
1068 << "), error=" << result;
1069 onMasterVolumeChanged(mMasterVolume);
1070 }
1071 return std::move(result);
Mikhail Naganov3b125b72022-10-05 02:12:39 +00001072 }
1073 LOG(ERROR) << __func__ << ": invalid master volume value: " << in_volume;
1074 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
1075}
1076
1077ndk::ScopedAStatus Module::getMicMute(bool* _aidl_return) {
1078 *_aidl_return = mMicMute;
1079 LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
1080 return ndk::ScopedAStatus::ok();
1081}
1082
1083ndk::ScopedAStatus Module::setMicMute(bool in_mute) {
1084 LOG(DEBUG) << __func__ << ": " << in_mute;
1085 mMicMute = in_mute;
1086 return ndk::ScopedAStatus::ok();
1087}
1088
Mikhail Naganovef6bc742022-10-06 00:14:19 +00001089ndk::ScopedAStatus Module::getMicrophones(std::vector<MicrophoneInfo>* _aidl_return) {
Pawan Wagh6f57cd92023-02-01 21:14:34 +00001090 *_aidl_return = getConfig().microphones;
Mikhail Naganovef6bc742022-10-06 00:14:19 +00001091 LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return);
1092 return ndk::ScopedAStatus::ok();
1093}
1094
Mikhail Naganov3b125b72022-10-05 02:12:39 +00001095ndk::ScopedAStatus Module::updateAudioMode(AudioMode in_mode) {
Mikhail Naganov04ae8222023-01-11 15:48:10 -08001096 if (!isValidAudioMode(in_mode)) {
1097 LOG(ERROR) << __func__ << ": invalid mode " << toString(in_mode);
1098 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
1099 }
Mikhail Naganov3b125b72022-10-05 02:12:39 +00001100 // No checks for supported audio modes here, it's an informative notification.
1101 LOG(DEBUG) << __func__ << ": " << toString(in_mode);
1102 return ndk::ScopedAStatus::ok();
1103}
1104
1105ndk::ScopedAStatus Module::updateScreenRotation(ScreenRotation in_rotation) {
1106 LOG(DEBUG) << __func__ << ": " << toString(in_rotation);
1107 return ndk::ScopedAStatus::ok();
1108}
1109
1110ndk::ScopedAStatus Module::updateScreenState(bool in_isTurnedOn) {
1111 LOG(DEBUG) << __func__ << ": " << in_isTurnedOn;
1112 return ndk::ScopedAStatus::ok();
1113}
1114
Vlad Popa83a6d822022-11-07 13:53:57 +01001115ndk::ScopedAStatus Module::getSoundDose(std::shared_ptr<ISoundDose>* _aidl_return) {
Mikhail Naganov7499a002023-02-27 18:51:44 -08001116 if (!mSoundDose) {
Vlad Popa2afbd1e2022-12-28 17:04:58 +01001117 mSoundDose = ndk::SharedRefBase::make<sounddose::SoundDose>();
Vlad Popa943b7e22022-12-08 14:24:12 +01001118 }
Mikhail Naganov7499a002023-02-27 18:51:44 -08001119 *_aidl_return = mSoundDose.getPtr();
Vlad Popa943b7e22022-12-08 14:24:12 +01001120 LOG(DEBUG) << __func__ << ": returning instance of ISoundDose: " << _aidl_return->get();
Vlad Popa83a6d822022-11-07 13:53:57 +01001121 return ndk::ScopedAStatus::ok();
1122}
1123
Mikhail Naganove9f10fc2022-10-14 23:31:52 +00001124ndk::ScopedAStatus Module::generateHwAvSyncId(int32_t* _aidl_return) {
1125 LOG(DEBUG) << __func__;
1126 (void)_aidl_return;
1127 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
1128}
1129
Mikhail Naganov20047bc2023-01-05 20:16:07 +00001130const std::string Module::VendorDebug::kForceTransientBurstName = "aosp.forceTransientBurst";
Mikhail Naganov194daaa2023-01-05 22:34:20 +00001131const std::string Module::VendorDebug::kForceSynchronousDrainName = "aosp.forceSynchronousDrain";
Mikhail Naganov20047bc2023-01-05 20:16:07 +00001132
Mikhail Naganove9f10fc2022-10-14 23:31:52 +00001133ndk::ScopedAStatus Module::getVendorParameters(const std::vector<std::string>& in_ids,
1134 std::vector<VendorParameter>* _aidl_return) {
1135 LOG(DEBUG) << __func__ << ": id count: " << in_ids.size();
Mikhail Naganov20047bc2023-01-05 20:16:07 +00001136 bool allParametersKnown = true;
1137 for (const auto& id : in_ids) {
1138 if (id == VendorDebug::kForceTransientBurstName) {
1139 VendorParameter forceTransientBurst{.id = id};
1140 forceTransientBurst.ext.setParcelable(Boolean{mVendorDebug.forceTransientBurst});
1141 _aidl_return->push_back(std::move(forceTransientBurst));
Mikhail Naganov194daaa2023-01-05 22:34:20 +00001142 } else if (id == VendorDebug::kForceSynchronousDrainName) {
1143 VendorParameter forceSynchronousDrain{.id = id};
1144 forceSynchronousDrain.ext.setParcelable(Boolean{mVendorDebug.forceSynchronousDrain});
1145 _aidl_return->push_back(std::move(forceSynchronousDrain));
Mikhail Naganov20047bc2023-01-05 20:16:07 +00001146 } else {
1147 allParametersKnown = false;
1148 LOG(ERROR) << __func__ << ": unrecognized parameter \"" << id << "\"";
1149 }
1150 }
1151 if (allParametersKnown) return ndk::ScopedAStatus::ok();
1152 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
Mikhail Naganove9f10fc2022-10-14 23:31:52 +00001153}
1154
Mikhail Naganov194daaa2023-01-05 22:34:20 +00001155namespace {
1156
1157template <typename W>
1158bool extractParameter(const VendorParameter& p, decltype(W::value)* v) {
1159 std::optional<W> value;
1160 binder_status_t result = p.ext.getParcelable(&value);
1161 if (result == STATUS_OK && value.has_value()) {
1162 *v = value.value().value;
1163 return true;
1164 }
1165 LOG(ERROR) << __func__ << ": failed to read the value of the parameter \"" << p.id
1166 << "\": " << result;
1167 return false;
1168}
1169
1170} // namespace
1171
Mikhail Naganove9f10fc2022-10-14 23:31:52 +00001172ndk::ScopedAStatus Module::setVendorParameters(const std::vector<VendorParameter>& in_parameters,
1173 bool in_async) {
1174 LOG(DEBUG) << __func__ << ": parameter count " << in_parameters.size()
1175 << ", async: " << in_async;
Mikhail Naganov20047bc2023-01-05 20:16:07 +00001176 bool allParametersKnown = true;
1177 for (const auto& p : in_parameters) {
1178 if (p.id == VendorDebug::kForceTransientBurstName) {
Mikhail Naganov194daaa2023-01-05 22:34:20 +00001179 if (!extractParameter<Boolean>(p, &mVendorDebug.forceTransientBurst)) {
1180 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
1181 }
1182 } else if (p.id == VendorDebug::kForceSynchronousDrainName) {
1183 if (!extractParameter<Boolean>(p, &mVendorDebug.forceSynchronousDrain)) {
Mikhail Naganov20047bc2023-01-05 20:16:07 +00001184 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
1185 }
1186 } else {
1187 allParametersKnown = false;
1188 LOG(ERROR) << __func__ << ": unrecognized parameter \"" << p.id << "\"";
1189 }
1190 }
1191 if (allParametersKnown) return ndk::ScopedAStatus::ok();
1192 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
Mikhail Naganove9f10fc2022-10-14 23:31:52 +00001193}
1194
Mikhail Naganovfb1acde2022-12-12 18:57:36 +00001195ndk::ScopedAStatus Module::addDeviceEffect(
1196 int32_t in_portConfigId,
1197 const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) {
1198 if (in_effect == nullptr) {
1199 LOG(DEBUG) << __func__ << ": port id " << in_portConfigId << ", null effect";
1200 } else {
1201 LOG(DEBUG) << __func__ << ": port id " << in_portConfigId << ", effect Binder "
1202 << in_effect->asBinder().get();
1203 }
1204 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
1205}
1206
1207ndk::ScopedAStatus Module::removeDeviceEffect(
1208 int32_t in_portConfigId,
1209 const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) {
1210 if (in_effect == nullptr) {
1211 LOG(DEBUG) << __func__ << ": port id " << in_portConfigId << ", null effect";
1212 } else {
1213 LOG(DEBUG) << __func__ << ": port id " << in_portConfigId << ", effect Binder "
1214 << in_effect->asBinder().get();
1215 }
1216 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
1217}
1218
jiabin9a8e6862023-01-12 23:06:37 +00001219ndk::ScopedAStatus Module::getMmapPolicyInfos(AudioMMapPolicyType mmapPolicyType,
1220 std::vector<AudioMMapPolicyInfo>* _aidl_return) {
1221 LOG(DEBUG) << __func__ << ": mmap policy type " << toString(mmapPolicyType);
1222 std::set<int32_t> mmapSinks;
1223 std::set<int32_t> mmapSources;
1224 auto& ports = getConfig().ports;
1225 for (const auto& port : ports) {
1226 if (port.flags.getTag() == AudioIoFlags::Tag::input &&
1227 isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::input>(),
1228 AudioInputFlags::MMAP_NOIRQ)) {
1229 mmapSinks.insert(port.id);
1230 } else if (port.flags.getTag() == AudioIoFlags::Tag::output &&
1231 isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
1232 AudioOutputFlags::MMAP_NOIRQ)) {
1233 mmapSources.insert(port.id);
1234 }
1235 }
1236 for (const auto& route : getConfig().routes) {
1237 if (mmapSinks.count(route.sinkPortId) != 0) {
1238 // The sink is a mix port, add the sources if they are device ports.
1239 for (int sourcePortId : route.sourcePortIds) {
1240 auto sourcePortIt = findById<AudioPort>(ports, sourcePortId);
1241 if (sourcePortIt == ports.end()) {
1242 // This must not happen
1243 LOG(ERROR) << __func__ << ": port id " << sourcePortId << " cannot be found";
1244 continue;
1245 }
1246 if (sourcePortIt->ext.getTag() != AudioPortExt::Tag::device) {
1247 // The source is not a device port, skip
1248 continue;
1249 }
1250 AudioMMapPolicyInfo policyInfo;
1251 policyInfo.device = sourcePortIt->ext.get<AudioPortExt::Tag::device>().device;
1252 // Always return AudioMMapPolicy.AUTO if the device supports mmap for
1253 // default implementation.
1254 policyInfo.mmapPolicy = AudioMMapPolicy::AUTO;
1255 _aidl_return->push_back(policyInfo);
1256 }
1257 } else {
1258 auto sinkPortIt = findById<AudioPort>(ports, route.sinkPortId);
1259 if (sinkPortIt == ports.end()) {
1260 // This must not happen
1261 LOG(ERROR) << __func__ << ": port id " << route.sinkPortId << " cannot be found";
1262 continue;
1263 }
1264 if (sinkPortIt->ext.getTag() != AudioPortExt::Tag::device) {
1265 // The sink is not a device port, skip
1266 continue;
1267 }
1268 if (count_any(mmapSources, route.sourcePortIds)) {
1269 AudioMMapPolicyInfo policyInfo;
1270 policyInfo.device = sinkPortIt->ext.get<AudioPortExt::Tag::device>().device;
1271 // Always return AudioMMapPolicy.AUTO if the device supports mmap for
1272 // default implementation.
1273 policyInfo.mmapPolicy = AudioMMapPolicy::AUTO;
1274 _aidl_return->push_back(policyInfo);
1275 }
1276 }
1277 }
1278 return ndk::ScopedAStatus::ok();
1279}
1280
Eric Laurente2432ea2023-01-12 17:47:31 +01001281ndk::ScopedAStatus Module::supportsVariableLatency(bool* _aidl_return) {
1282 LOG(DEBUG) << __func__;
1283 *_aidl_return = false;
1284 return ndk::ScopedAStatus::ok();
1285}
1286
jiabinb76981e2023-01-18 00:58:30 +00001287ndk::ScopedAStatus Module::getAAudioMixerBurstCount(int32_t* _aidl_return) {
1288 if (!isMmapSupported()) {
1289 LOG(DEBUG) << __func__ << ": mmap is not supported ";
1290 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
1291 }
1292 *_aidl_return = DEFAULT_AAUDIO_MIXER_BURST_COUNT;
1293 LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
1294 return ndk::ScopedAStatus::ok();
1295}
1296
1297ndk::ScopedAStatus Module::getAAudioHardwareBurstMinUsec(int32_t* _aidl_return) {
1298 if (!isMmapSupported()) {
1299 LOG(DEBUG) << __func__ << ": mmap is not supported ";
1300 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
1301 }
1302 *_aidl_return = DEFAULT_AAUDIO_HARDWARE_BURST_MIN_DURATION_US;
1303 LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
1304 return ndk::ScopedAStatus::ok();
1305}
1306
1307bool Module::isMmapSupported() {
1308 if (mIsMmapSupported.has_value()) {
1309 return mIsMmapSupported.value();
1310 }
1311 std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
1312 if (!getMmapPolicyInfos(AudioMMapPolicyType::DEFAULT, &mmapPolicyInfos).isOk()) {
1313 mIsMmapSupported = false;
1314 } else {
1315 mIsMmapSupported =
1316 std::find_if(mmapPolicyInfos.begin(), mmapPolicyInfos.end(), [](const auto& info) {
1317 return info.mmapPolicy == AudioMMapPolicy::AUTO ||
1318 info.mmapPolicy == AudioMMapPolicy::ALWAYS;
1319 }) != mmapPolicyInfos.end();
1320 }
1321 return mIsMmapSupported.value();
1322}
1323
Mikhail Naganov9d16a6a2023-06-26 17:21:04 -07001324ndk::ScopedAStatus Module::createInputStream(const SinkMetadata& sinkMetadata,
1325 StreamContext&& context,
1326 const std::vector<MicrophoneInfo>& microphones,
1327 std::shared_ptr<StreamIn>* result) {
1328 return createStreamInstance<StreamInStub>(result, sinkMetadata, std::move(context),
1329 microphones);
1330}
1331
1332ndk::ScopedAStatus Module::createOutputStream(const SourceMetadata& sourceMetadata,
1333 StreamContext&& context,
1334 const std::optional<AudioOffloadInfo>& offloadInfo,
1335 std::shared_ptr<StreamOut>* result) {
1336 return createStreamInstance<StreamOutStub>(result, sourceMetadata, std::move(context),
1337 offloadInfo);
1338}
1339
jiabin253bd322023-01-25 23:57:31 +00001340ndk::ScopedAStatus Module::populateConnectedDevicePort(AudioPort* audioPort __unused) {
jiabin116d8392023-03-01 22:52:57 +00001341 LOG(VERBOSE) << __func__ << ": do nothing and return ok";
jiabin253bd322023-01-25 23:57:31 +00001342 return ndk::ScopedAStatus::ok();
1343}
1344
1345ndk::ScopedAStatus Module::checkAudioPatchEndpointsMatch(
1346 const std::vector<AudioPortConfig*>& sources __unused,
1347 const std::vector<AudioPortConfig*>& sinks __unused) {
jiabin116d8392023-03-01 22:52:57 +00001348 LOG(VERBOSE) << __func__ << ": do nothing and return ok";
jiabin253bd322023-01-25 23:57:31 +00001349 return ndk::ScopedAStatus::ok();
1350}
1351
jiabin783c48b2023-02-28 18:28:06 +00001352void Module::onExternalDeviceConnectionChanged(
1353 const ::aidl::android::media::audio::common::AudioPort& audioPort __unused,
1354 bool connected __unused) {
1355 LOG(DEBUG) << __func__ << ": do nothing and return";
1356}
1357
1358ndk::ScopedAStatus Module::onMasterMuteChanged(bool mute __unused) {
1359 LOG(VERBOSE) << __func__ << ": do nothing and return ok";
1360 return ndk::ScopedAStatus::ok();
1361}
1362
1363ndk::ScopedAStatus Module::onMasterVolumeChanged(float volume __unused) {
1364 LOG(VERBOSE) << __func__ << ": do nothing and return ok";
1365 return ndk::ScopedAStatus::ok();
1366}
1367
Mikhail Naganovdf5adfd2021-11-11 22:09:22 +00001368} // namespace aidl::android::hardware::audio::core