blob: e2233c7201befa440b8f63fb3b1de2d36d26f377 [file] [log] [blame]
Shunkai Yao51202502022-12-12 06:11:46 +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#define LOG_TAG "DeviceHalAidl"
Mikhail Naganov89a9f742023-01-30 12:33:18 -080018// #define LOG_NDEBUG 0
Shunkai Yao51202502022-12-12 06:11:46 +000019
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080020#include <algorithm>
21#include <forward_list>
22
Mikhail Naganovdfd594e2023-02-08 16:59:41 -080023#include <aidl/android/hardware/audio/core/BnStreamCallback.h>
24#include <aidl/android/hardware/audio/core/BnStreamOutEventCallback.h>
Mikhail Naganovfab697c2023-01-11 19:33:13 +000025#include <aidl/android/hardware/audio/core/StreamDescriptor.h>
26#include <error/expected_utils.h>
27#include <media/AidlConversionCppNdk.h>
Mikhail Naganov25bc9a22023-04-21 18:48:16 -070028#include <media/AidlConversionNdkCpp.h>
Mikhail Naganovfab697c2023-01-11 19:33:13 +000029#include <media/AidlConversionUtil.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000030#include <mediautils/TimeCheck.h>
Mikhail Naganov89a9f742023-01-30 12:33:18 -080031#include <Utils.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000032#include <utils/Log.h>
Shunkai Yao51202502022-12-12 06:11:46 +000033
Mikhail Naganov31d46652023-01-10 18:29:25 +000034#include "DeviceHalAidl.h"
Mikhail Naganova82a69d2023-06-14 16:31:32 -070035#include "EffectHalAidl.h"
Mikhail Naganov31d46652023-01-10 18:29:25 +000036#include "StreamHalAidl.h"
37
Mikhail Naganovfab697c2023-01-11 19:33:13 +000038using aidl::android::aidl_utils::statusTFromBinderStatus;
Mikhail Naganovccc82112023-04-27 18:14:15 -070039using aidl::android::media::audio::common::Boolean;
Mikhail Naganove93a0862023-03-15 17:06:59 -070040using aidl::android::media::audio::common::AudioChannelLayout;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080041using aidl::android::media::audio::common::AudioConfig;
42using aidl::android::media::audio::common::AudioDevice;
David Li9cf5e622023-03-21 00:51:10 +080043using aidl::android::media::audio::common::AudioDeviceAddress;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080044using aidl::android::media::audio::common::AudioDeviceType;
Mikhail Naganov69557132023-09-07 15:29:01 -070045using aidl::android::media::audio::common::AudioFormatDescription;
Mikhail Naganove93a0862023-03-15 17:06:59 -070046using aidl::android::media::audio::common::AudioFormatType;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080047using aidl::android::media::audio::common::AudioInputFlags;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080048using aidl::android::media::audio::common::AudioIoFlags;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -080049using aidl::android::media::audio::common::AudioLatencyMode;
David Li9cf5e622023-03-21 00:51:10 +080050using aidl::android::media::audio::common::AudioMMapPolicy;
51using aidl::android::media::audio::common::AudioMMapPolicyInfo;
52using aidl::android::media::audio::common::AudioMMapPolicyType;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000053using aidl::android::media::audio::common::AudioMode;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080054using aidl::android::media::audio::common::AudioOutputFlags;
55using aidl::android::media::audio::common::AudioPort;
56using aidl::android::media::audio::common::AudioPortConfig;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080057using aidl::android::media::audio::common::AudioPortDeviceExt;
David Li9cf5e622023-03-21 00:51:10 +080058using aidl::android::media::audio::common::AudioPortExt;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -080059using aidl::android::media::audio::common::AudioPortMixExt;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -080060using aidl::android::media::audio::common::AudioPortMixExtUseCase;
Mikhail Naganove93a0862023-03-15 17:06:59 -070061using aidl::android::media::audio::common::AudioProfile;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080062using aidl::android::media::audio::common::AudioSource;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000063using aidl::android::media::audio::common::Float;
David Li9cf5e622023-03-21 00:51:10 +080064using aidl::android::media::audio::common::Int;
65using aidl::android::media::audio::common::MicrophoneDynamicInfo;
66using aidl::android::media::audio::common::MicrophoneInfo;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -070067using aidl::android::media::audio::IHalAdapterVendorExtension;
Mikhail Naganov6352e822023-03-09 18:22:36 -080068using aidl::android::hardware::audio::common::getFrameSizeInBytes;
69using aidl::android::hardware::audio::common::isBitPositionFlagSet;
Mikhail Naganove93a0862023-03-15 17:06:59 -070070using aidl::android::hardware::audio::common::isDefaultAudioFormat;
Mikhail Naganov6352e822023-03-09 18:22:36 -080071using aidl::android::hardware::audio::common::makeBitPositionFlagMask;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080072using aidl::android::hardware::audio::common::RecordTrackMetadata;
73using aidl::android::hardware::audio::core::AudioPatch;
Mikhail Naganov289468a2023-03-29 10:06:15 -070074using aidl::android::hardware::audio::core::AudioRoute;
Mikhail Naganovccc82112023-04-27 18:14:15 -070075using aidl::android::hardware::audio::core::IBluetooth;
76using aidl::android::hardware::audio::core::IBluetoothA2dp;
77using aidl::android::hardware::audio::core::IBluetoothLe;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000078using aidl::android::hardware::audio::core::IModule;
79using aidl::android::hardware::audio::core::ITelephony;
Mikhail Naganove93a0862023-03-15 17:06:59 -070080using aidl::android::hardware::audio::core::ModuleDebug;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000081using aidl::android::hardware::audio::core::StreamDescriptor;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -070082using aidl::android::hardware::audio::core::VendorParameter;
Mikhail Naganov31d46652023-01-10 18:29:25 +000083
84namespace android {
85
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080086namespace {
87
88bool isConfigEqualToPortConfig(const AudioConfig& config, const AudioPortConfig& portConfig) {
89 return portConfig.sampleRate.value().value == config.base.sampleRate &&
90 portConfig.channelMask.value() == config.base.channelMask &&
91 portConfig.format.value() == config.base.format;
92}
93
94void setConfigFromPortConfig(AudioConfig* config, const AudioPortConfig& portConfig) {
95 config->base.sampleRate = portConfig.sampleRate.value().value;
96 config->base.channelMask = portConfig.channelMask.value();
97 config->base.format = portConfig.format.value();
98}
99
100void setPortConfigFromConfig(AudioPortConfig* portConfig, const AudioConfig& config) {
Mikhail Naganov69557132023-09-07 15:29:01 -0700101 if (config.base.sampleRate != 0) {
102 portConfig->sampleRate = Int{ .value = config.base.sampleRate };
103 }
104 if (config.base.channelMask != AudioChannelLayout{}) {
105 portConfig->channelMask = config.base.channelMask;
106 }
107 if (config.base.format != AudioFormatDescription{}) {
108 portConfig->format = config.base.format;
109 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800110}
111
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700112// Note: these converters are for types defined in different AIDL files. Although these
113// AIDL files are copies of each other, however formally these are different types
114// thus we don't use a conversion via a parcelable.
115ConversionResult<media::AudioRoute> ndk2cpp_AudioRoute(const AudioRoute& ndk) {
116 media::AudioRoute cpp;
117 cpp.sourcePortIds.insert(
118 cpp.sourcePortIds.end(), ndk.sourcePortIds.begin(), ndk.sourcePortIds.end());
119 cpp.sinkPortId = ndk.sinkPortId;
120 cpp.isExclusive = ndk.isExclusive;
David Li9cf5e622023-03-21 00:51:10 +0800121 return cpp;
122}
123
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700124template<typename T>
125std::shared_ptr<T> retrieveSubInterface(const std::shared_ptr<IModule>& module,
126 ::ndk::ScopedAStatus (IModule::*getT)(std::shared_ptr<T>*)) {
127 if (module != nullptr) {
128 std::shared_ptr<T> instance;
129 if (auto status = (module.get()->*getT)(&instance); status.isOk()) {
130 return instance;
131 }
132 }
133 return nullptr;
134}
135
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800136} // namespace
137
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700138DeviceHalAidl::DeviceHalAidl(const std::string& instance, const std::shared_ptr<IModule>& module,
139 const std::shared_ptr<IHalAdapterVendorExtension>& vext)
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700140 : ConversionHelperAidl("DeviceHalAidl"),
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700141 mInstance(instance), mModule(module), mVendorExt(vext),
Mikhail Naganovccc82112023-04-27 18:14:15 -0700142 mTelephony(retrieveSubInterface<ITelephony>(module, &IModule::getTelephony)),
143 mBluetooth(retrieveSubInterface<IBluetooth>(module, &IModule::getBluetooth)),
144 mBluetoothA2dp(retrieveSubInterface<IBluetoothA2dp>(module, &IModule::getBluetoothA2dp)),
145 mBluetoothLe(retrieveSubInterface<IBluetoothLe>(module, &IModule::getBluetoothLe)) {
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700146}
147
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700148status_t DeviceHalAidl::getAudioPorts(std::vector<media::audio::common::AudioPort> *ports) {
Mikhail Naganov9e459d72023-05-05 17:36:39 -0700149 return ::aidl::android::convertContainer(mPorts, ports,
150 [](const Ports::value_type& pair) { return ndk2cpp_AudioPort(pair.second); });
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700151}
152
153status_t DeviceHalAidl::getAudioRoutes(std::vector<media::AudioRoute> *routes) {
154 *routes = VALUE_OR_RETURN_STATUS(
155 ::aidl::android::convertContainer<std::vector<media::AudioRoute>>(
156 mRoutes, ndk2cpp_AudioRoute));
157 return OK;
158}
159
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700160status_t DeviceHalAidl::getSupportedModes(std::vector<media::audio::common::AudioMode> *modes) {
161 TIME_CHECK();
162 if (modes == nullptr) {
163 return BAD_VALUE;
164 }
165 if (mModule == nullptr) return NO_INIT;
166 if (mTelephony == nullptr) return INVALID_OPERATION;
167 std::vector<AudioMode> aidlModes;
168 RETURN_STATUS_IF_ERROR(
169 statusTFromBinderStatus(mTelephony->getSupportedAudioModes(&aidlModes)));
170 *modes = VALUE_OR_RETURN_STATUS(
171 ::aidl::android::convertContainer<std::vector<media::audio::common::AudioMode>>(
172 aidlModes, ndk2cpp_AudioMode));
173 return OK;
174}
175
Mikhail Naganov31d46652023-01-10 18:29:25 +0000176status_t DeviceHalAidl::getSupportedDevices(uint32_t*) {
177 // Obsolete.
178 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +0000179}
180
181status_t DeviceHalAidl::initCheck() {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800182 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000183 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800184 std::vector<AudioPort> ports;
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700185 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800186 ALOGW_IF(ports.empty(), "%s: module %s returned an empty list of audio ports",
187 __func__, mInstance.c_str());
188 std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()),
189 [](const auto& p) { return std::make_pair(p.id, p); });
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800190 mDefaultInputPortId = mDefaultOutputPortId = -1;
191 const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
192 for (const auto& pair : mPorts) {
193 const auto& p = pair.second;
194 if (p.ext.getTag() == AudioPortExt::Tag::device &&
195 (p.ext.get<AudioPortExt::Tag::device>().flags & defaultDeviceFlag) != 0) {
196 if (p.flags.getTag() == AudioIoFlags::Tag::input) {
197 mDefaultInputPortId = p.id;
198 } else if (p.flags.getTag() == AudioIoFlags::Tag::output) {
199 mDefaultOutputPortId = p.id;
200 }
201 }
202 }
203 ALOGI("%s: module %s default port ids: input %d, output %d",
204 __func__, mInstance.c_str(), mDefaultInputPortId, mDefaultOutputPortId);
Mikhail Naganov289468a2023-03-29 10:06:15 -0700205 RETURN_STATUS_IF_ERROR(updateRoutes());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800206 std::vector<AudioPortConfig> portConfigs;
207 RETURN_STATUS_IF_ERROR(
208 statusTFromBinderStatus(mModule->getAudioPortConfigs(&portConfigs))); // OK if empty
209 std::transform(portConfigs.begin(), portConfigs.end(),
210 std::inserter(mPortConfigs, mPortConfigs.end()),
211 [](const auto& p) { return std::make_pair(p.id, p); });
jiabin9c07faf2023-04-26 22:00:44 +0000212 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
213 std::inserter(mInitialPortConfigIds, mInitialPortConfigIds.end()),
214 [](const auto& pcPair) { return pcPair.first; });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800215 std::vector<AudioPatch> patches;
216 RETURN_STATUS_IF_ERROR(
217 statusTFromBinderStatus(mModule->getAudioPatches(&patches))); // OK if empty
218 std::transform(patches.begin(), patches.end(),
219 std::inserter(mPatches, mPatches.end()),
220 [](const auto& p) { return std::make_pair(p.id, p); });
Shunkai Yao51202502022-12-12 06:11:46 +0000221 return OK;
222}
223
224status_t DeviceHalAidl::setVoiceVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000225 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000226 if (!mModule) return NO_INIT;
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700227 if (mTelephony == nullptr) return INVALID_OPERATION;
228 ITelephony::TelecomConfig inConfig{ .voiceVolume = Float{volume} }, outConfig;
229 RETURN_STATUS_IF_ERROR(
230 statusTFromBinderStatus(mTelephony->setTelecomConfig(inConfig, &outConfig)));
231 ALOGW_IF(outConfig.voiceVolume.has_value() && volume != outConfig.voiceVolume.value().value,
232 "%s: the resulting voice volume %f is not the same as requested %f",
233 __func__, outConfig.voiceVolume.value().value, volume);
234 return OK;
Shunkai Yao51202502022-12-12 06:11:46 +0000235}
236
237status_t DeviceHalAidl::setMasterVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000238 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000239 if (!mModule) return NO_INIT;
240 return statusTFromBinderStatus(mModule->setMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000241}
242
243status_t DeviceHalAidl::getMasterVolume(float *volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000244 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000245 if (!mModule) return NO_INIT;
246 return statusTFromBinderStatus(mModule->getMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000247}
248
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000249status_t DeviceHalAidl::setMode(audio_mode_t mode) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000250 TIME_CHECK();
251 if (!mModule) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000252 AudioMode audioMode = VALUE_OR_FATAL(::aidl::android::legacy2aidl_audio_mode_t_AudioMode(mode));
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700253 if (mTelephony != nullptr) {
254 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mTelephony->switchAudioMode(audioMode)));
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000255 }
256 return statusTFromBinderStatus(mModule->updateAudioMode(audioMode));
Shunkai Yao51202502022-12-12 06:11:46 +0000257}
258
259status_t DeviceHalAidl::setMicMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000260 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000261 if (!mModule) return NO_INIT;
262 return statusTFromBinderStatus(mModule->setMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000263}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000264
Shunkai Yao51202502022-12-12 06:11:46 +0000265status_t DeviceHalAidl::getMicMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000266 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000267 if (!mModule) return NO_INIT;
268 return statusTFromBinderStatus(mModule->getMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000269}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000270
Shunkai Yao51202502022-12-12 06:11:46 +0000271status_t DeviceHalAidl::setMasterMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000272 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000273 if (!mModule) return NO_INIT;
274 return statusTFromBinderStatus(mModule->setMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000275}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000276
Shunkai Yao51202502022-12-12 06:11:46 +0000277status_t DeviceHalAidl::getMasterMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000278 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000279 if (!mModule) return NO_INIT;
280 return statusTFromBinderStatus(mModule->getMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000281}
282
Mikhail Naganovccc82112023-04-27 18:14:15 -0700283status_t DeviceHalAidl::setParameters(const String8& kvPairs) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000284 if (!mModule) return NO_INIT;
Mikhail Naganovccc82112023-04-27 18:14:15 -0700285 AudioParameter parameters(kvPairs);
286 ALOGD("%s: parameters: \"%s\"", __func__, parameters.toString().c_str());
287
288 if (status_t status = filterAndUpdateBtA2dpParameters(parameters); status != OK) {
289 ALOGW("%s: filtering or updating BT A2DP parameters failed: %d", __func__, status);
290 }
291 if (status_t status = filterAndUpdateBtHfpParameters(parameters); status != OK) {
292 ALOGW("%s: filtering or updating BT HFP parameters failed: %d", __func__, status);
293 }
294 if (status_t status = filterAndUpdateBtLeParameters(parameters); status != OK) {
295 ALOGW("%s: filtering or updating BT LE parameters failed: %d", __func__, status);
296 }
297 if (status_t status = filterAndUpdateBtScoParameters(parameters); status != OK) {
298 ALOGW("%s: filtering or updating BT SCO parameters failed: %d", __func__, status);
299 }
Mikhail Naganove92c34b2023-05-31 14:24:48 -0700300 if (status_t status = filterAndUpdateScreenParameters(parameters); status != OK) {
301 ALOGW("%s: filtering or updating screen parameters failed: %d", __func__, status);
302 }
Mikhail Naganovb9a81312023-07-18 13:55:34 -0700303 if (status_t status = filterAndUpdateTelephonyParameters(parameters); status != OK) {
304 ALOGW("%s: filtering or updating telephony parameters failed: %d", __func__, status);
305 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700306 return parseAndSetVendorParameters(mVendorExt, mModule, parameters);
Shunkai Yao51202502022-12-12 06:11:46 +0000307}
308
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700309status_t DeviceHalAidl::getParameters(const String8& keys, String8 *values) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000310 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000311 if (!mModule) return NO_INIT;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700312 if (values == nullptr) {
313 return BAD_VALUE;
314 }
315 AudioParameter parameterKeys(keys), result;
316 if (status_t status = filterAndRetrieveBtA2dpParameters(parameterKeys, &result); status != OK) {
317 ALOGW("%s: filtering or retrieving BT A2DP parameters failed: %d", __func__, status);
318 }
319 *values = result.toString();
320 return parseAndGetVendorParameters(mVendorExt, mModule, parameterKeys, values);
Shunkai Yao51202502022-12-12 06:11:46 +0000321}
322
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800323namespace {
324
325class Cleanup {
326 public:
327 typedef void (DeviceHalAidl::*Cleaner)(int32_t);
328
329 Cleanup(DeviceHalAidl* device, Cleaner cleaner, int32_t id) :
330 mDevice(device), mCleaner(cleaner), mId(id) {}
331 ~Cleanup() { clean(); }
332 void clean() {
333 if (mDevice != nullptr) (mDevice->*mCleaner)(mId);
334 disarm();
335 }
336 void disarm() { mDevice = nullptr; }
337
338 private:
339 DeviceHalAidl* mDevice;
340 const Cleaner mCleaner;
341 const int32_t mId;
342};
343
344} // namespace
345
346// Since the order of container elements destruction is unspecified,
347// ensure that cleanups are performed from the most recent one and upwards.
348// This is the same as if there were individual Cleanup instances on the stack,
349// however the bonus is that we can disarm all of them with just one statement.
350class DeviceHalAidl::Cleanups : public std::forward_list<Cleanup> {
351 public:
352 ~Cleanups() { for (auto& c : *this) c.clean(); }
353 void disarmAll() { for (auto& c : *this) c.disarm(); }
354};
355
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800356status_t DeviceHalAidl::getInputBufferSize(const struct audio_config* config, size_t* size) {
357 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
358 if (size == nullptr) return BAD_VALUE;
359 TIME_CHECK();
360 if (!mModule) return NO_INIT;
361 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
362 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
363 AudioDevice aidlDevice;
364 aidlDevice.type.type = AudioDeviceType::IN_DEFAULT;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800365 AudioSource aidlSource = AudioSource::DEFAULT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800366 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
367 AudioPortConfig mixPortConfig;
368 Cleanups cleanups;
369 audio_config writableConfig = *config;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700370 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800371 RETURN_STATUS_IF_ERROR(prepareToOpenStream(0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700372 &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800373 *size = aidlConfig.frameCount *
374 getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
375 // Do not disarm cleanups to release temporary port configs.
376 return OK;
377}
378
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800379status_t DeviceHalAidl::prepareToOpenStream(
380 int32_t aidlHandle, const AudioDevice& aidlDevice, const AudioIoFlags& aidlFlags,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800381 AudioSource aidlSource, struct audio_config* config,
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800382 Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700383 AudioPatch* aidlPatch) {
384 ALOGD("%p %s::%s: handle %d, device %s, flags %s, source %s, config %s, mix port config %s",
385 this, getClassName().c_str(), __func__, aidlHandle, aidlDevice.toString().c_str(),
386 aidlFlags.toString().c_str(), toString(aidlSource).c_str(),
387 aidlConfig->toString().c_str(), mixPortConfig->toString().c_str());
jiabin9c07faf2023-04-26 22:00:44 +0000388 resetUnusedPatchesAndPortConfigs();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800389 const bool isInput = aidlFlags.getTag() == AudioIoFlags::Tag::input;
390 // Find / create AudioPortConfigs for the device port and the mix port,
391 // then find / create a patch between them, and open a stream on the mix port.
392 AudioPortConfig devicePortConfig;
393 bool created = false;
jiabin9c07faf2023-04-26 22:00:44 +0000394 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, aidlConfig,
395 &devicePortConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800396 if (created) {
397 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
398 }
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800399 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*aidlConfig, aidlFlags, aidlHandle, aidlSource,
Mikhail Naganov289468a2023-03-29 10:06:15 -0700400 std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800401 if (created) {
402 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
403 }
404 setConfigFromPortConfig(aidlConfig, *mixPortConfig);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800405 if (isInput) {
406 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700407 {devicePortConfig.id}, {mixPortConfig->id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800408 } else {
409 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700410 {mixPortConfig->id}, {devicePortConfig.id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800411 }
412 if (created) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700413 cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, aidlPatch->id);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800414 }
415 if (aidlConfig->frameCount <= 0) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700416 aidlConfig->frameCount = aidlPatch->minimumStreamBufferSizeFrames;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800417 }
418 *config = VALUE_OR_RETURN_STATUS(
419 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(*aidlConfig, isInput));
420 return OK;
421}
422
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800423namespace {
424
425class StreamCallbackBase {
426 protected:
427 explicit StreamCallbackBase(const sp<CallbackBroker>& broker) : mBroker(broker) {}
428 public:
429 void* getCookie() const { return mCookie; }
430 void setCookie(void* cookie) { mCookie = cookie; }
431 sp<CallbackBroker> getBroker() const {
432 if (void* cookie = mCookie; cookie != nullptr) return mBroker.promote();
433 return nullptr;
434 }
435 private:
436 const wp<CallbackBroker> mBroker;
437 std::atomic<void*> mCookie;
438};
439
440template<class C>
441class StreamCallbackBaseHelper {
442 protected:
443 explicit StreamCallbackBaseHelper(const StreamCallbackBase& base) : mBase(base) {}
444 sp<C> getCb(const sp<CallbackBroker>& broker, void* cookie);
445 using CbRef = const sp<C>&;
446 ndk::ScopedAStatus runCb(const std::function<void(CbRef cb)>& f) {
447 if (auto cb = getCb(mBase.getBroker(), mBase.getCookie()); cb != nullptr) f(cb);
448 return ndk::ScopedAStatus::ok();
449 }
450 private:
451 const StreamCallbackBase& mBase;
452};
453
454template<>
455sp<StreamOutHalInterfaceCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>::getCb(
456 const sp<CallbackBroker>& broker, void* cookie) {
457 if (broker != nullptr) return broker->getStreamOutCallback(cookie);
458 return nullptr;
459}
460
461template<>
462sp<StreamOutHalInterfaceEventCallback>
463StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::getCb(
464 const sp<CallbackBroker>& broker, void* cookie) {
465 if (broker != nullptr) return broker->getStreamOutEventCallback(cookie);
466 return nullptr;
467}
468
469template<>
470sp<StreamOutHalInterfaceLatencyModeCallback>
471StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::getCb(
472 const sp<CallbackBroker>& broker, void* cookie) {
473 if (broker != nullptr) return broker->getStreamOutLatencyModeCallback(cookie);
474 return nullptr;
475}
476
477/*
478Note on the callback ownership.
479
480In the Binder ownership model, the server implementation is kept alive
481as long as there is any client (proxy object) alive. This is done by
482incrementing the refcount of the server-side object by the Binder framework.
483When it detects that the last client is gone, it decrements the refcount back.
484
485Thus, it is not needed to keep any references to StreamCallback on our
486side (after we have sent an instance to the client), because we are
487the server-side. The callback object will be kept alive as long as the HAL server
488holds a strong ref to IStreamCallback proxy.
489*/
490
491class OutputStreamCallbackAidl : public StreamCallbackBase,
492 public StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>,
493 public ::aidl::android::hardware::audio::core::BnStreamCallback {
494 public:
495 explicit OutputStreamCallbackAidl(const sp<CallbackBroker>& broker)
496 : StreamCallbackBase(broker),
497 StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>(
498 *static_cast<StreamCallbackBase*>(this)) {}
499 ndk::ScopedAStatus onTransferReady() override {
500 return runCb([](CbRef cb) { cb->onWriteReady(); });
501 }
502 ndk::ScopedAStatus onError() override {
503 return runCb([](CbRef cb) { cb->onError(); });
504 }
505 ndk::ScopedAStatus onDrainReady() override {
506 return runCb([](CbRef cb) { cb->onDrainReady(); });
507 }
508};
509
510class OutputStreamEventCallbackAidl :
511 public StreamCallbackBase,
512 public StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>,
513 public StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>,
514 public ::aidl::android::hardware::audio::core::BnStreamOutEventCallback {
515 public:
516 explicit OutputStreamEventCallbackAidl(const sp<CallbackBroker>& broker)
517 : StreamCallbackBase(broker),
518 StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>(
519 *static_cast<StreamCallbackBase*>(this)),
520 StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>(
521 *static_cast<StreamCallbackBase*>(this)) {}
522 ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& in_audioMetadata) override {
523 std::basic_string<uint8_t> halMetadata(in_audioMetadata.begin(), in_audioMetadata.end());
524 return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb(
525 [&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); });
526 }
527 ndk::ScopedAStatus onRecommendedLatencyModeChanged(
528 const std::vector<AudioLatencyMode>& in_modes) override {
529 auto halModes = VALUE_OR_FATAL(
530 ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
531 in_modes,
532 ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
533 return StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::runCb(
534 [&halModes](auto cb) { cb->onRecommendedLatencyModeChanged(halModes); });
535 }
536};
537
538} // namespace
539
Mikhail Naganov31d46652023-01-10 18:29:25 +0000540status_t DeviceHalAidl::openOutputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800541 audio_io_handle_t handle, audio_devices_t devices,
542 audio_output_flags_t flags, struct audio_config* config,
543 const char* address,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000544 sp<StreamOutHalInterface>* outStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800545 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000546 if (!outStream || !config) {
547 return BAD_VALUE;
548 }
549 TIME_CHECK();
550 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800551 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
552 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
553 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
554 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, false /*isInput*/));
555 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
556 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
557 int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
558 ::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
559 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
560 AudioPortConfig mixPortConfig;
561 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700562 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800563 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
564 AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700565 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800566 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
567 args.portConfigId = mixPortConfig.id;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800568 const bool isOffload = isBitPositionFlagSet(
569 aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD);
570 std::shared_ptr<OutputStreamCallbackAidl> streamCb;
571 if (isOffload) {
572 streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
573 }
574 auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
575 if (isOffload) {
576 args.offloadInfo = aidlConfig.offloadInfo;
577 args.callback = streamCb;
578 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800579 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800580 args.eventCallback = eventCb;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800581 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
582 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800583 StreamContextAidl context(ret.desc, isOffload);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800584 if (!context.isValid()) {
585 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
586 __func__, ret.desc.toString().c_str());
587 return NO_INIT;
588 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700589 *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700590 std::move(ret.stream), mVendorExt, this /*callbackBroker*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700591 mStreams.insert(std::pair(*outStream, aidlPatch.id));
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800592 void* cbCookie = (*outStream).get();
593 {
594 std::lock_guard l(mLock);
595 mCallbacks.emplace(cbCookie, Callbacks{});
596 }
597 if (streamCb) streamCb->setCookie(cbCookie);
598 eventCb->setCookie(cbCookie);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800599 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000600 return OK;
601}
602
Mikhail Naganov31d46652023-01-10 18:29:25 +0000603status_t DeviceHalAidl::openInputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800604 audio_io_handle_t handle, audio_devices_t devices,
605 struct audio_config* config, audio_input_flags_t flags,
606 const char* address, audio_source_t source,
607 audio_devices_t outputDevice, const char* outputDeviceAddress,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000608 sp<StreamInHalInterface>* inStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800609 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000610 if (!inStream || !config) {
611 return BAD_VALUE;
612 }
613 TIME_CHECK();
614 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800615 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
616 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
617 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
618 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
619 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
620 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
621 int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
622 ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
623 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
624 AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
625 ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
626 AudioPortConfig mixPortConfig;
627 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700628 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800629 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700630 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800631 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
632 args.portConfigId = mixPortConfig.id;
633 RecordTrackMetadata aidlTrackMetadata{
634 .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
635 if (outputDevice != AUDIO_DEVICE_NONE) {
636 aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
637 ::aidl::android::legacy2aidl_audio_device_AudioDevice(
638 outputDevice, outputDeviceAddress));
639 }
640 args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
641 args.bufferSizeFrames = aidlConfig.frameCount;
642 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
643 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800644 StreamContextAidl context(ret.desc, false /*isAsynchronous*/);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800645 if (!context.isValid()) {
646 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
647 __func__, ret.desc.toString().c_str());
648 return NO_INIT;
649 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700650 *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700651 std::move(ret.stream), mVendorExt, this /*micInfoProvider*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700652 mStreams.insert(std::pair(*inStream, aidlPatch.id));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800653 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000654 return OK;
655}
656
657status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
658 *supportsPatches = true;
659 return OK;
660}
661
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800662status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
663 const struct audio_port_config* sources,
664 unsigned int num_sinks,
665 const struct audio_port_config* sinks,
666 audio_patch_handle_t* patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800667 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000668 TIME_CHECK();
669 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800670 if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
671 sources == nullptr || sinks == nullptr || patch == nullptr) {
672 return BAD_VALUE;
673 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800674 // When the patch handle (*patch) is AUDIO_PATCH_HANDLE_NONE, it means
675 // the framework wants to create a new patch. The handle has to be generated
676 // by the HAL. Since handles generated this way can only be unique within
677 // a HAL module, the framework generates a globally unique handle, and maps
678 // it on the <HAL module, patch handle> pair.
679 // When the patch handle is set, it meant the framework intends to update
680 // an existing patch.
681 //
682 // This behavior corresponds to HAL module behavior, with the only difference
683 // that the HAL module uses `int32_t` for patch IDs. The following assert ensures
684 // that both the framework and the HAL use the same value for "no ID":
685 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
686 int32_t halPatchId = static_cast<int32_t>(*patch);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800687
688 // Upon conversion, mix port configs contain audio configuration, while
689 // device port configs contain device address. This data is used to find
690 // or create HAL configs.
691 std::vector<AudioPortConfig> aidlSources, aidlSinks;
692 for (unsigned int i = 0; i < num_sources; ++i) {
693 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
694 sources[i].role, sources[i].type)) ==
695 ::aidl::android::AudioPortDirection::INPUT;
696 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
697 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
698 sources[i], isInput, 0)));
699 }
700 for (unsigned int i = 0; i < num_sinks; ++i) {
701 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
702 sinks[i].role, sinks[i].type)) ==
703 ::aidl::android::AudioPortDirection::INPUT;
704 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
705 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
706 sinks[i], isInput, 0)));
707 }
708 Cleanups cleanups;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800709 auto existingPatchIt = halPatchId != 0 ? mPatches.find(halPatchId): mPatches.end();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800710 AudioPatch aidlPatch;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800711 if (existingPatchIt != mPatches.end()) {
712 aidlPatch = existingPatchIt->second;
713 aidlPatch.sourcePortConfigIds.clear();
714 aidlPatch.sinkPortConfigIds.clear();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800715 }
Mikhail Naganov02038012023-09-08 12:38:14 -0700716 // The IDs will be found by 'fillPortConfigs', however the original 'aidlSources' and
717 // 'aidlSinks' will not be updated because 'setAudioPatch' only needs IDs. Here we log
718 // the source arguments, where only the audio configuration and device specifications
719 // are relevant.
720 ALOGD("%s: [disregard IDs] sources: %s, sinks: %s",
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800721 __func__, ::android::internal::ToString(aidlSources).c_str(),
722 ::android::internal::ToString(aidlSinks).c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800723 auto fillPortConfigs = [&](
Mikhail Naganov289468a2023-03-29 10:06:15 -0700724 const std::vector<AudioPortConfig>& configs,
725 const std::set<int32_t>& destinationPortIds,
726 std::vector<int32_t>* ids, std::set<int32_t>* portIds) -> status_t {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800727 for (const auto& s : configs) {
728 AudioPortConfig portConfig;
729 bool created = false;
Mikhail Naganov289468a2023-03-29 10:06:15 -0700730 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
731 s, destinationPortIds, &portConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800732 if (created) {
733 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, portConfig.id);
734 }
735 ids->push_back(portConfig.id);
Mikhail Naganov289468a2023-03-29 10:06:15 -0700736 if (portIds != nullptr) {
737 portIds->insert(portConfig.portId);
738 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800739 }
740 return OK;
741 };
Mikhail Naganov289468a2023-03-29 10:06:15 -0700742 // When looking up port configs, the destinationPortId is only used for mix ports.
743 // Thus, we process device port configs first, and look up the destination port ID from them.
744 bool sourceIsDevice = std::any_of(aidlSources.begin(), aidlSources.end(),
745 [](const auto& config) { return config.ext.getTag() == AudioPortExt::device; });
746 const std::vector<AudioPortConfig>& devicePortConfigs =
747 sourceIsDevice ? aidlSources : aidlSinks;
748 std::vector<int32_t>* devicePortConfigIds =
749 sourceIsDevice ? &aidlPatch.sourcePortConfigIds : &aidlPatch.sinkPortConfigIds;
750 const std::vector<AudioPortConfig>& mixPortConfigs =
751 sourceIsDevice ? aidlSinks : aidlSources;
752 std::vector<int32_t>* mixPortConfigIds =
753 sourceIsDevice ? &aidlPatch.sinkPortConfigIds : &aidlPatch.sourcePortConfigIds;
754 std::set<int32_t> devicePortIds;
755 RETURN_STATUS_IF_ERROR(fillPortConfigs(
756 devicePortConfigs, std::set<int32_t>(), devicePortConfigIds, &devicePortIds));
757 RETURN_STATUS_IF_ERROR(fillPortConfigs(
758 mixPortConfigs, devicePortIds, mixPortConfigIds, nullptr));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800759 if (existingPatchIt != mPatches.end()) {
760 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
761 mModule->setAudioPatch(aidlPatch, &aidlPatch)));
762 existingPatchIt->second = aidlPatch;
763 } else {
764 bool created = false;
765 RETURN_STATUS_IF_ERROR(findOrCreatePatch(aidlPatch, &aidlPatch, &created));
766 // Since no cleanup of the patch is needed, 'created' is ignored.
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800767 halPatchId = aidlPatch.id;
768 *patch = static_cast<audio_patch_handle_t>(halPatchId);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800769 }
770 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000771 return OK;
772}
773
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800774status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800775 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000776 TIME_CHECK();
777 if (!mModule) return NO_INIT;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800778 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
779 if (patch == AUDIO_PATCH_HANDLE_NONE) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800780 return BAD_VALUE;
781 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800782 int32_t halPatchId = static_cast<int32_t>(patch);
783 auto patchIt = mPatches.find(halPatchId);
784 if (patchIt == mPatches.end()) {
785 ALOGE("%s: patch with id %d not found", __func__, halPatchId);
786 return BAD_VALUE;
787 }
788 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->resetAudioPatch(halPatchId)));
789 mPatches.erase(patchIt);
Shunkai Yao51202502022-12-12 06:11:46 +0000790 return OK;
791}
792
Mikhail Naganove93a0862023-03-15 17:06:59 -0700793status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
794 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000795 TIME_CHECK();
796 if (!mModule) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700797 if (port == nullptr) {
798 return BAD_VALUE;
799 }
800 audio_port_v7 portV7;
801 audio_populate_audio_port_v7(port, &portV7);
802 RETURN_STATUS_IF_ERROR(getAudioPort(&portV7));
803 return audio_populate_audio_port(&portV7, port) ? OK : BAD_VALUE;
804}
805
806status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
807 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
808 TIME_CHECK();
809 if (!mModule) return NO_INIT;
810 if (port == nullptr) {
811 return BAD_VALUE;
812 }
813 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
814 ::aidl::android::AudioPortDirection::INPUT;
815 auto aidlPort = VALUE_OR_RETURN_STATUS(
816 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
817 if (aidlPort.ext.getTag() != AudioPortExt::device) {
818 ALOGE("%s: provided port is not a device port (module %s): %s",
819 __func__, mInstance.c_str(), aidlPort.toString().c_str());
820 return BAD_VALUE;
821 }
822 const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
823 // It seems that we don't have to call HAL since all valid ports have been added either
824 // during initialization, or while handling connection of an external device.
825 auto portsIt = findPort(matchDevice);
826 if (portsIt == mPorts.end()) {
827 ALOGE("%s: device port for device %s is not found in the module %s",
828 __func__, matchDevice.toString().c_str(), mInstance.c_str());
829 return BAD_VALUE;
830 }
831 const int32_t fwkId = aidlPort.id;
832 aidlPort = portsIt->second;
833 aidlPort.id = fwkId;
834 *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
835 aidlPort, isInput));
836 return OK;
837}
838
jiabin12537fc2023-10-12 17:56:08 +0000839status_t DeviceHalAidl::getAudioMixPort(const struct audio_port_v7 *devicePort,
840 struct audio_port_v7 *mixPort) {
841 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
842 if (devicePort->type != AUDIO_PORT_TYPE_DEVICE) {
843 return BAD_VALUE;
844 }
845 if (mixPort->type != AUDIO_PORT_TYPE_MIX) {
846 return BAD_VALUE;
847 }
848 const int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
849 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(mixPort->ext.mix.handle));
850 auto it = findPortConfig(std::nullopt /*config*/, std::nullopt/*flags*/, aidlHandle);
851 if (it == mPortConfigs.end()) {
852 ALOGE("%s, cannot find mix port config for handle=%u", __func__, aidlHandle);
853 return BAD_VALUE;
854 }
855 AudioPort port;
856 if (status_t status = getAudioPort(it->second.portId, &port); status != NO_ERROR) {
857 return status;
858 }
859 const bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
860 mixPort->role, mixPort->type)) == ::aidl::android::AudioPortDirection::INPUT;
861 *mixPort = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
862 port, isInput));
863 return NO_ERROR;
864}
865
Mikhail Naganove93a0862023-03-15 17:06:59 -0700866status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
867 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
868 TIME_CHECK();
869 if (!mModule) return NO_INIT;
870 if (config == nullptr) {
871 return BAD_VALUE;
872 }
873 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
874 config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
875 AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
876 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
877 *config, isInput, 0 /*portId*/));
878 AudioPortConfig portConfig;
879 bool created = false;
Mikhail Naganov289468a2023-03-29 10:06:15 -0700880 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
881 requestedPortConfig, std::set<int32_t>(), &portConfig, &created));
Shunkai Yao51202502022-12-12 06:11:46 +0000882 return OK;
883}
884
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800885MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
886 if (mMicrophones.status == Microphones::Status::UNKNOWN) {
887 TIME_CHECK();
888 std::vector<MicrophoneInfo> aidlInfo;
889 status_t status = statusTFromBinderStatus(mModule->getMicrophones(&aidlInfo));
890 if (status == OK) {
891 mMicrophones.status = Microphones::Status::QUERIED;
892 mMicrophones.info = std::move(aidlInfo);
893 } else if (status == INVALID_OPERATION) {
894 mMicrophones.status = Microphones::Status::NOT_SUPPORTED;
895 } else {
896 ALOGE("%s: Unexpected status from 'IModule.getMicrophones': %d", __func__, status);
897 return {};
898 }
899 }
900 if (mMicrophones.status == Microphones::Status::QUERIED) {
901 return &mMicrophones.info;
902 }
903 return {}; // NOT_SUPPORTED
904}
905
Shunkai Yao51202502022-12-12 06:11:46 +0000906status_t DeviceHalAidl::getMicrophones(
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800907 std::vector<audio_microphone_characteristic_t>* microphones) {
908 if (!microphones) {
909 return BAD_VALUE;
910 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000911 TIME_CHECK();
912 if (!mModule) return NO_INIT;
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800913 auto staticInfo = getMicrophoneInfo();
914 if (!staticInfo) return INVALID_OPERATION;
915 std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
916 emptyDynamicInfo.reserve(staticInfo->size());
917 std::transform(staticInfo->begin(), staticInfo->end(), std::back_inserter(emptyDynamicInfo),
918 [](const auto& info) { return MicrophoneDynamicInfo{ .id = info.id }; });
919 *microphones = VALUE_OR_RETURN_STATUS(
920 ::aidl::android::convertContainers<std::vector<audio_microphone_characteristic_t>>(
921 *staticInfo, emptyDynamicInfo,
922 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t)
923 );
Shunkai Yao51202502022-12-12 06:11:46 +0000924 return OK;
925}
926
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700927status_t DeviceHalAidl::addDeviceEffect(
928 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
929 TIME_CHECK();
930 if (!mModule) return NO_INIT;
Shunkai Yao51202502022-12-12 06:11:46 +0000931 if (!effect) {
932 return BAD_VALUE;
933 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700934 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
935 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
936 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
937 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
938 *device, isInput, 0));
939 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
940 ALOGE("%s: provided port config is not a device port config: %s",
941 __func__, requestedPortConfig.toString().c_str());
942 return BAD_VALUE;
943 }
944 AudioPortConfig devicePortConfig;
945 bool created;
946 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
947 requestedPortConfig, {} /*destinationPortIds*/, &devicePortConfig, &created));
948 Cleanups cleanups;
949 if (created) {
950 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
951 }
952 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
953 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->addDeviceEffect(
954 devicePortConfig.id, aidlEffect->getIEffect())));
955 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000956 return OK;
957}
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700958status_t DeviceHalAidl::removeDeviceEffect(
959 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
960 TIME_CHECK();
961 if (!mModule) return NO_INIT;
Shunkai Yao51202502022-12-12 06:11:46 +0000962 if (!effect) {
963 return BAD_VALUE;
964 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700965 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
966 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
967 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
968 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
969 *device, isInput, 0));
970 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
971 ALOGE("%s: provided port config is not a device port config: %s",
972 __func__, requestedPortConfig.toString().c_str());
973 return BAD_VALUE;
974 }
975 auto existingPortConfigIt = findPortConfig(
976 requestedPortConfig.ext.get<AudioPortExt::Tag::device>().device);
977 if (existingPortConfigIt == mPortConfigs.end()) {
978 ALOGE("%s: could not find a configured device port for the config %s",
979 __func__, requestedPortConfig.toString().c_str());
980 return BAD_VALUE;
981 }
982 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
983 return statusTFromBinderStatus(mModule->removeDeviceEffect(
984 existingPortConfigIt->first, aidlEffect->getIEffect()));
Shunkai Yao51202502022-12-12 06:11:46 +0000985}
986
987status_t DeviceHalAidl::getMmapPolicyInfos(
David Li9cf5e622023-03-21 00:51:10 +0800988 media::audio::common::AudioMMapPolicyType policyType,
989 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000990 TIME_CHECK();
Mikhail Naganov25bc9a22023-04-21 18:48:16 -0700991 AudioMMapPolicyType mmapPolicyType = VALUE_OR_RETURN_STATUS(
992 cpp2ndk_AudioMMapPolicyType(policyType));
David Li9cf5e622023-03-21 00:51:10 +0800993
994 std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
995
996 if (status_t status = statusTFromBinderStatus(
997 mModule->getMmapPolicyInfos(mmapPolicyType, &mmapPolicyInfos)); status != OK) {
998 return status;
999 }
1000
1001 *policyInfos = VALUE_OR_RETURN_STATUS(
1002 convertContainer<std::vector<media::audio::common::AudioMMapPolicyInfo>>(
1003 mmapPolicyInfos, ndk2cpp_AudioMMapPolicyInfo));
Shunkai Yao51202502022-12-12 06:11:46 +00001004 return OK;
1005}
1006
1007int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganov31d46652023-01-10 18:29:25 +00001008 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +08001009 int32_t mixerBurstCount = 0;
1010 if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
1011 return mixerBurstCount;
1012 }
1013 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +00001014}
1015
1016int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganov31d46652023-01-10 18:29:25 +00001017 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +08001018 int32_t hardwareBurstMinUsec = 0;
1019 if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
1020 return hardwareBurstMinUsec;
1021 }
1022 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +00001023}
1024
1025error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganov31d46652023-01-10 18:29:25 +00001026 TIME_CHECK();
Mikhail Naganov08a62ab2023-03-14 17:11:51 -07001027 if (!mModule) return NO_INIT;
1028 int32_t aidlHwAvSync;
1029 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
1030 return VALUE_OR_RETURN_STATUS(
1031 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +00001032}
1033
Mikhail Naganovfab697c2023-01-11 19:33:13 +00001034status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
1035 TIME_CHECK();
1036 if (!mModule) return NO_INIT;
1037 return mModule->dump(fd, Args(args).args(), args.size());
David Li9cf5e622023-03-21 00:51:10 +08001038}
Shunkai Yao51202502022-12-12 06:11:46 +00001039
Eric Laurent7af6ee72023-06-29 11:44:54 +02001040status_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
Mikhail Naganov31d46652023-01-10 18:29:25 +00001041 TIME_CHECK();
Mikhail Naganov3ac95c92023-04-12 13:14:30 -07001042 if (!mModule) return NO_INIT;
1043 if (supports == nullptr) {
1044 return BAD_VALUE;
1045 }
1046 return statusTFromBinderStatus(mModule->supportsVariableLatency(supports));
Shunkai Yao51202502022-12-12 06:11:46 +00001047}
Mikhail Naganov31d46652023-01-10 18:29:25 +00001048
Vlad Popa03bd5bc2023-01-17 16:16:51 +01001049status_t DeviceHalAidl::getSoundDoseInterface(const std::string& module,
1050 ::ndk::SpAIBinder* soundDoseBinder) {
1051 TIME_CHECK();
1052 if (!mModule) return NO_INIT;
1053 if (mSoundDose == nullptr) {
1054 ndk::ScopedAStatus status = mModule->getSoundDose(&mSoundDose);
1055 if (!status.isOk()) {
1056 ALOGE("%s failed to return the sound dose interface for module %s: %s",
1057 __func__,
1058 module.c_str(),
1059 status.getDescription().c_str());
1060 return BAD_VALUE;
1061 }
1062 }
1063 *soundDoseBinder = mSoundDose->asBinder();
1064 ALOGI("%s using audio AIDL HAL sound dose interface", __func__);
1065
1066 return OK;
1067}
jiabin872de702023-04-27 22:04:31 +00001068
1069status_t DeviceHalAidl::prepareToDisconnectExternalDevice(const struct audio_port_v7* port) {
1070 // There is not AIDL API defined for `prepareToDisconnectExternalDevice`.
1071 // Call `setConnectedState` instead.
1072 // TODO(b/279824103): call prepareToDisconnectExternalDevice when it is added.
Mikhail Naganov66907492023-09-11 17:22:03 -07001073 if (const status_t status = setConnectedState(port, false /*connected*/); status == NO_ERROR) {
jiabin872de702023-04-27 22:04:31 +00001074 mDeviceDisconnectionNotified.insert(port->id);
1075 }
Mikhail Naganov66907492023-09-11 17:22:03 -07001076 // Return that there was no error as otherwise the disconnection procedure will not be
1077 // considered complete for upper layers, and 'setConnectedState' will not be called again.
1078 return NO_ERROR;
jiabin872de702023-04-27 22:04:31 +00001079}
1080
Mikhail Naganove93a0862023-03-15 17:06:59 -07001081status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
1082 TIME_CHECK();
1083 if (!mModule) return NO_INIT;
1084 if (port == nullptr) {
1085 return BAD_VALUE;
1086 }
jiabin872de702023-04-27 22:04:31 +00001087 if (!connected && mDeviceDisconnectionNotified.erase(port->id) > 0) {
1088 // For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
1089 // and then call `setConnectedState`. However, there is no API for
1090 // `prepareToDisconnectExternalDevice` yet. In that case, `setConnectedState` will be
1091 // called when calling `prepareToDisconnectExternalDevice`. Do not call to the HAL if
1092 // previous call is successful. Also remove the cache here to avoid a large cache after
1093 // a long run.
1094 return NO_ERROR;
1095 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001096 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
1097 ::aidl::android::AudioPortDirection::INPUT;
1098 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
1099 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
1100 if (aidlPort.ext.getTag() != AudioPortExt::device) {
1101 ALOGE("%s: provided port is not a device port (module %s): %s",
1102 __func__, mInstance.c_str(), aidlPort.toString().c_str());
1103 return BAD_VALUE;
1104 }
1105 if (connected) {
1106 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1107 // Reset the device address to find the "template" port.
1108 matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
1109 auto portsIt = findPort(matchDevice);
1110 if (portsIt == mPorts.end()) {
Mikhail Naganov69557132023-09-07 15:29:01 -07001111 // Since 'setConnectedState' is called for all modules, it is normal when the device
1112 // port not found in every one of them.
Mikhail Naganove93a0862023-03-15 17:06:59 -07001113 return BAD_VALUE;
Mikhail Naganov02038012023-09-08 12:38:14 -07001114 } else {
1115 ALOGD("%s: device port for device %s found in the module %s",
1116 __func__, matchDevice.toString().c_str(), mInstance.c_str());
Mikhail Naganove93a0862023-03-15 17:06:59 -07001117 }
Mikhail Naganov66907492023-09-11 17:22:03 -07001118 resetUnusedPatchesAndPortConfigs();
Mikhail Naganove93a0862023-03-15 17:06:59 -07001119 // Use the ID of the "template" port, use all the information from the provided port.
1120 aidlPort.id = portsIt->first;
1121 AudioPort connectedPort;
1122 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
1123 aidlPort, &connectedPort)));
1124 const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
1125 LOG_ALWAYS_FATAL_IF(!inserted,
1126 "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
1127 __func__, mInstance.c_str(), connectedPort.toString().c_str(),
1128 it->second.toString().c_str());
Mikhail Naganov892f7612023-09-15 18:55:39 -07001129 mConnectedPorts[connectedPort.id] = false;
Mikhail Naganove93a0862023-03-15 17:06:59 -07001130 } else { // !connected
1131 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1132 auto portsIt = findPort(matchDevice);
1133 if (portsIt == mPorts.end()) {
Mikhail Naganov02038012023-09-08 12:38:14 -07001134 // Since 'setConnectedState' is called for all modules, it is normal when the device
1135 // port not found in every one of them.
Mikhail Naganove93a0862023-03-15 17:06:59 -07001136 return BAD_VALUE;
Mikhail Naganov02038012023-09-08 12:38:14 -07001137 } else {
1138 ALOGD("%s: device port for device %s found in the module %s",
1139 __func__, matchDevice.toString().c_str(), mInstance.c_str());
Mikhail Naganove93a0862023-03-15 17:06:59 -07001140 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001141 resetUnusedPatchesAndPortConfigs();
Mikhail Naganov66907492023-09-11 17:22:03 -07001142 // Streams are closed by AudioFlinger independently from device disconnections.
1143 // It is possible that the stream has not been closed yet.
1144 const int32_t portId = portsIt->second.id;
1145 if (!isPortHeldByAStream(portId)) {
1146 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1147 mModule->disconnectExternalDevice(portId)));
1148 mPorts.erase(portsIt);
Mikhail Naganov892f7612023-09-15 18:55:39 -07001149 mConnectedPorts.erase(portId);
Mikhail Naganov66907492023-09-11 17:22:03 -07001150 } else {
1151 ALOGD("%s: since device port ID %d is used by a stream, "
1152 "external device disconnection postponed", __func__, portId);
Mikhail Naganov892f7612023-09-15 18:55:39 -07001153 mConnectedPorts[portId] = true;
Mikhail Naganov66907492023-09-11 17:22:03 -07001154 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001155 }
Mikhail Naganov289468a2023-03-29 10:06:15 -07001156 return updateRoutes();
Mikhail Naganove93a0862023-03-15 17:06:59 -07001157}
1158
1159status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
1160 TIME_CHECK();
1161 if (!mModule) return NO_INIT;
Mikhail Naganov66907492023-09-11 17:22:03 -07001162 resetUnusedPatchesAndPortConfigs();
Mikhail Naganove93a0862023-03-15 17:06:59 -07001163 ModuleDebug debug{ .simulateDeviceConnections = enabled };
1164 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
1165 // This is important to log as it affects HAL behavior.
1166 if (status == OK) {
1167 ALOGI("%s: set enabled: %d", __func__, enabled);
1168 } else {
1169 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
1170 }
1171 return status;
1172}
1173
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001174bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
1175 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1176 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1177}
1178
1179bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
1180 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1181 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1182 return p.portId == mDefaultInputPortId;
1183 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1184 return p.portId == mDefaultOutputPortId;
1185 }
1186 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1187}
1188
David Lia8675d42023-03-30 21:08:06 +08001189status_t DeviceHalAidl::createOrUpdatePortConfig(
1190 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool* created) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001191 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001192 AudioPortConfig appliedPortConfig;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001193 bool applied = false;
1194 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001195 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001196 if (!applied) {
1197 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001198 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001199 if (!applied) {
1200 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001201 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001202 return NO_INIT;
1203 }
1204 }
David Lia8675d42023-03-30 21:08:06 +08001205
1206 int32_t id = appliedPortConfig.id;
1207 if (requestedPortConfig.id != 0 && requestedPortConfig.id != id) {
1208 LOG_ALWAYS_FATAL("%s: requested port config id %d changed to %d", __func__,
1209 requestedPortConfig.id, id);
1210 }
1211
1212 auto [it, inserted] = mPortConfigs.insert_or_assign(std::move(id),
1213 std::move(appliedPortConfig));
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001214 *result = it;
David Lia8675d42023-03-30 21:08:06 +08001215 *created = inserted;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001216 return OK;
1217}
1218
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001219status_t DeviceHalAidl::filterAndRetrieveBtA2dpParameters(
1220 AudioParameter &keys, AudioParameter *result) {
1221 TIME_CHECK();
1222 if (String8 key = String8(AudioParameter::keyReconfigA2dpSupported); keys.containsKey(key)) {
1223 keys.remove(key);
David Lia7761ed2023-11-03 17:22:07 +00001224 if (mBluetoothA2dp != nullptr) {
1225 bool supports;
1226 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1227 mBluetoothA2dp->supportsOffloadReconfiguration(&supports)));
1228 result->addInt(key, supports ? 1 : 0);
1229 } else {
1230 ALOGI("%s: no IBluetoothA2dp on %s", __func__, mInstance.c_str());
1231 result->addInt(key, 0);
1232 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001233 }
1234 return OK;
1235}
1236
Mikhail Naganovccc82112023-04-27 18:14:15 -07001237status_t DeviceHalAidl::filterAndUpdateBtA2dpParameters(AudioParameter &parameters) {
1238 TIME_CHECK();
1239 std::optional<bool> a2dpEnabled;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001240 std::optional<std::vector<VendorParameter>> reconfigureOffload;
Mikhail Naganovccc82112023-04-27 18:14:15 -07001241 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1242 parameters, String8(AudioParameter::keyBtA2dpSuspended),
1243 [&a2dpEnabled](const String8& trueOrFalse) {
1244 if (trueOrFalse == AudioParameter::valueTrue) {
1245 a2dpEnabled = false; // 'suspended' == true
1246 return OK;
1247 } else if (trueOrFalse == AudioParameter::valueFalse) {
1248 a2dpEnabled = true; // 'suspended' == false
1249 return OK;
1250 }
1251 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1252 AudioParameter::keyBtA2dpSuspended, trueOrFalse.c_str());
1253 return BAD_VALUE;
1254 }));
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001255 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1256 parameters, String8(AudioParameter::keyReconfigA2dp),
1257 [&](const String8& value) -> status_t {
1258 if (mVendorExt != nullptr) {
1259 std::vector<VendorParameter> result;
1260 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1261 mVendorExt->parseBluetoothA2dpReconfigureOffload(
1262 std::string(value.c_str()), &result)));
1263 reconfigureOffload = std::move(result);
1264 } else {
1265 reconfigureOffload = std::vector<VendorParameter>();
1266 }
1267 return OK;
1268 }));
Mikhail Naganovccc82112023-04-27 18:14:15 -07001269 if (mBluetoothA2dp != nullptr && a2dpEnabled.has_value()) {
1270 return statusTFromBinderStatus(mBluetoothA2dp->setEnabled(a2dpEnabled.value()));
1271 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001272 if (mBluetoothA2dp != nullptr && reconfigureOffload.has_value()) {
1273 return statusTFromBinderStatus(mBluetoothA2dp->reconfigureOffload(
1274 reconfigureOffload.value()));
1275 }
Mikhail Naganovccc82112023-04-27 18:14:15 -07001276 return OK;
1277}
1278
1279status_t DeviceHalAidl::filterAndUpdateBtHfpParameters(AudioParameter &parameters) {
1280 TIME_CHECK();
1281 IBluetooth::HfpConfig hfpConfig;
1282 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1283 parameters, String8(AudioParameter::keyBtHfpEnable),
1284 [&hfpConfig](const String8& trueOrFalse) {
1285 if (trueOrFalse == AudioParameter::valueTrue) {
1286 hfpConfig.isEnabled = Boolean{ .value = true };
1287 return OK;
1288 } else if (trueOrFalse == AudioParameter::valueFalse) {
1289 hfpConfig.isEnabled = Boolean{ .value = false };
1290 return OK;
1291 }
1292 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1293 AudioParameter::keyBtHfpEnable, trueOrFalse.c_str());
1294 return BAD_VALUE;
1295 }));
1296 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1297 parameters, String8(AudioParameter::keyBtHfpSamplingRate),
1298 [&hfpConfig](int sampleRate) {
1299 return sampleRate > 0 ?
1300 hfpConfig.sampleRate = Int{ .value = sampleRate }, OK : BAD_VALUE;
1301 }));
1302 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1303 parameters, String8(AudioParameter::keyBtHfpVolume),
1304 [&hfpConfig](int volume0to15) {
1305 if (volume0to15 >= 0 && volume0to15 <= 15) {
1306 hfpConfig.volume = Float{ .value = volume0to15 / 15.0f };
1307 return OK;
1308 }
1309 return BAD_VALUE;
1310 }));
1311 if (mBluetooth != nullptr && hfpConfig != IBluetooth::HfpConfig{}) {
1312 IBluetooth::HfpConfig newHfpConfig;
1313 return statusTFromBinderStatus(mBluetooth->setHfpConfig(hfpConfig, &newHfpConfig));
1314 }
1315 return OK;
1316}
1317
1318status_t DeviceHalAidl::filterAndUpdateBtLeParameters(AudioParameter &parameters) {
1319 TIME_CHECK();
1320 std::optional<bool> leEnabled;
1321 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1322 parameters, String8(AudioParameter::keyBtLeSuspended),
1323 [&leEnabled](const String8& trueOrFalse) {
1324 if (trueOrFalse == AudioParameter::valueTrue) {
1325 leEnabled = false; // 'suspended' == true
1326 return OK;
1327 } else if (trueOrFalse == AudioParameter::valueFalse) {
1328 leEnabled = true; // 'suspended' == false
1329 return OK;
1330 }
1331 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1332 AudioParameter::keyBtLeSuspended, trueOrFalse.c_str());
1333 return BAD_VALUE;
1334 }));
1335 if (mBluetoothLe != nullptr && leEnabled.has_value()) {
1336 return statusTFromBinderStatus(mBluetoothLe->setEnabled(leEnabled.value()));
1337 }
1338 return OK;
1339}
1340
1341status_t DeviceHalAidl::filterAndUpdateBtScoParameters(AudioParameter &parameters) {
1342 TIME_CHECK();
1343 IBluetooth::ScoConfig scoConfig;
1344 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1345 parameters, String8(AudioParameter::keyBtSco),
1346 [&scoConfig](const String8& onOrOff) {
1347 if (onOrOff == AudioParameter::valueOn) {
1348 scoConfig.isEnabled = Boolean{ .value = true };
1349 return OK;
1350 } else if (onOrOff == AudioParameter::valueOff) {
1351 scoConfig.isEnabled = Boolean{ .value = false };
1352 return OK;
1353 }
1354 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1355 AudioParameter::keyBtSco, onOrOff.c_str());
1356 return BAD_VALUE;
1357 }));
1358 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1359 parameters, String8(AudioParameter::keyBtScoHeadsetName),
1360 [&scoConfig](const String8& name) {
1361 scoConfig.debugName = name;
1362 return OK;
1363 }));
1364 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1365 parameters, String8(AudioParameter::keyBtNrec),
1366 [&scoConfig](const String8& onOrOff) {
1367 if (onOrOff == AudioParameter::valueOn) {
1368 scoConfig.isNrecEnabled = Boolean{ .value = true };
1369 return OK;
1370 } else if (onOrOff == AudioParameter::valueOff) {
1371 scoConfig.isNrecEnabled = Boolean{ .value = false };
1372 return OK;
1373 }
1374 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1375 AudioParameter::keyBtNrec, onOrOff.c_str());
1376 return BAD_VALUE;
1377 }));
1378 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1379 parameters, String8(AudioParameter::keyBtScoWb),
1380 [&scoConfig](const String8& onOrOff) {
1381 if (onOrOff == AudioParameter::valueOn) {
1382 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO_WB;
1383 return OK;
1384 } else if (onOrOff == AudioParameter::valueOff) {
1385 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO;
1386 return OK;
1387 }
1388 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1389 AudioParameter::keyBtScoWb, onOrOff.c_str());
1390 return BAD_VALUE;
1391 }));
1392 if (mBluetooth != nullptr && scoConfig != IBluetooth::ScoConfig{}) {
1393 IBluetooth::ScoConfig newScoConfig;
1394 return statusTFromBinderStatus(mBluetooth->setScoConfig(scoConfig, &newScoConfig));
1395 }
1396 return OK;
1397}
1398
Mikhail Naganove92c34b2023-05-31 14:24:48 -07001399status_t DeviceHalAidl::filterAndUpdateScreenParameters(AudioParameter &parameters) {
1400 TIME_CHECK();
1401 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1402 parameters, String8(AudioParameter::keyScreenState),
1403 [&](const String8& onOrOff) -> status_t {
1404 std::optional<bool> isTurnedOn;
1405 if (onOrOff == AudioParameter::valueOn) {
1406 isTurnedOn = true;
1407 } else if (onOrOff == AudioParameter::valueOff) {
1408 isTurnedOn = false;
1409 }
1410 if (!isTurnedOn.has_value()) {
1411 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1412 AudioParameter::keyScreenState, onOrOff.c_str());
1413 return BAD_VALUE;
1414 }
1415 return statusTFromBinderStatus(
1416 mModule->updateScreenState(isTurnedOn.value()));
1417 }));
1418 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1419 parameters, String8(AudioParameter::keyScreenRotation),
1420 [&](int rotationDegrees) -> status_t {
1421 IModule::ScreenRotation rotation;
1422 switch (rotationDegrees) {
1423 case 0: rotation = IModule::ScreenRotation::DEG_0; break;
1424 case 90: rotation = IModule::ScreenRotation::DEG_90; break;
1425 case 180: rotation = IModule::ScreenRotation::DEG_180; break;
1426 case 270: rotation = IModule::ScreenRotation::DEG_270; break;
1427 default:
1428 ALOGE("setParameters: parameter key \"%s\" has invalid value %d",
1429 AudioParameter::keyScreenRotation, rotationDegrees);
1430 return BAD_VALUE;
1431 }
1432 return statusTFromBinderStatus(mModule->updateScreenRotation(rotation));
1433 }));
1434 return OK;
1435}
1436
Mikhail Naganovb9a81312023-07-18 13:55:34 -07001437status_t DeviceHalAidl::filterAndUpdateTelephonyParameters(AudioParameter &parameters) {
1438 TIME_CHECK();
1439 using TtyMode = ITelephony::TelecomConfig::TtyMode;
1440 ITelephony::TelecomConfig telConfig;
1441 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1442 parameters, String8(AudioParameter::keyTtyMode),
1443 [&telConfig](const String8& mode) {
1444 if (mode == AudioParameter::valueTtyModeOff) {
1445 telConfig.ttyMode = TtyMode::OFF;
1446 return OK;
1447 } else if (mode == AudioParameter::valueTtyModeFull) {
1448 telConfig.ttyMode = TtyMode::FULL;
1449 return OK;
1450 } else if (mode == AudioParameter::valueTtyModeHco) {
1451 telConfig.ttyMode = TtyMode::HCO;
1452 return OK;
1453 } else if (mode == AudioParameter::valueTtyModeVco) {
1454 telConfig.ttyMode = TtyMode::VCO;
1455 return OK;
1456 }
1457 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1458 AudioParameter::keyTtyMode, mode.c_str());
1459 return BAD_VALUE;
1460 }));
1461 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1462 parameters, String8(AudioParameter::keyHacSetting),
1463 [&telConfig](const String8& onOrOff) {
1464 if (onOrOff == AudioParameter::valueHacOn) {
1465 telConfig.isHacEnabled = Boolean{ .value = true };
1466 return OK;
1467 } else if (onOrOff == AudioParameter::valueHacOff) {
1468 telConfig.isHacEnabled = Boolean{ .value = false };
1469 return OK;
1470 }
1471 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1472 AudioParameter::keyHacSetting, onOrOff.c_str());
1473 return BAD_VALUE;
1474 }));
1475 if (mTelephony != nullptr && telConfig != ITelephony::TelecomConfig{}) {
1476 ITelephony::TelecomConfig newTelConfig;
1477 return statusTFromBinderStatus(
1478 mTelephony->setTelecomConfig(telConfig, &newTelConfig));
1479 }
1480 return OK;
1481}
1482
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001483status_t DeviceHalAidl::findOrCreatePatch(
1484 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
1485 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
1486 requestedPatch.sourcePortConfigIds.end());
1487 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
1488 requestedPatch.sinkPortConfigIds.end());
1489 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
1490}
1491
1492status_t DeviceHalAidl::findOrCreatePatch(
1493 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
1494 AudioPatch* patch, bool* created) {
1495 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
1496 if (patchIt == mPatches.end()) {
1497 TIME_CHECK();
1498 AudioPatch requestedPatch, appliedPatch;
1499 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
1500 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
1501 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
1502 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
1503 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
1504 requestedPatch, &appliedPatch)));
1505 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
1506 *created = true;
1507 } else {
1508 *created = false;
1509 }
1510 *patch = patchIt->second;
1511 return OK;
1512}
1513
jiabin9c07faf2023-04-26 22:00:44 +00001514status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device, const AudioConfig* config,
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001515 AudioPortConfig* portConfig, bool* created) {
1516 auto portConfigIt = findPortConfig(device);
1517 if (portConfigIt == mPortConfigs.end()) {
1518 auto portsIt = findPort(device);
1519 if (portsIt == mPorts.end()) {
1520 ALOGE("%s: device port for device %s is not found in the module %s",
1521 __func__, device.toString().c_str(), mInstance.c_str());
1522 return BAD_VALUE;
1523 }
1524 AudioPortConfig requestedPortConfig;
1525 requestedPortConfig.portId = portsIt->first;
jiabin9c07faf2023-04-26 22:00:44 +00001526 if (config != nullptr) {
1527 setPortConfigFromConfig(&requestedPortConfig, *config);
1528 }
David Lia8675d42023-03-30 21:08:06 +08001529 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1530 created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001531 } else {
1532 *created = false;
1533 }
1534 *portConfig = portConfigIt->second;
1535 return OK;
1536}
1537
1538status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001539 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001540 AudioSource source, const std::set<int32_t>& destinationPortIds,
1541 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001542 // These flags get removed one by one in this order when retrying port finding.
1543 static const std::vector<AudioInputFlags> kOptionalInputFlags{
1544 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001545 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001546 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001547 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
1548 AudioIoFlags matchFlags = flags.value();
Mikhail Naganov289468a2023-03-29 10:06:15 -07001549 auto portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001550 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
1551 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
1552 if (!isBitPositionFlagSet(
1553 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
1554 ++optionalInputFlagsIt;
1555 continue;
1556 }
1557 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
1558 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
Mikhail Naganov289468a2023-03-29 10:06:15 -07001559 portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001560 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
1561 "retried with flags %s", __func__, config.toString().c_str(),
1562 flags.value().toString().c_str(), mInstance.c_str(),
1563 matchFlags.toString().c_str());
1564 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001565 if (portsIt == mPorts.end()) {
1566 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001567 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001568 mInstance.c_str());
1569 return BAD_VALUE;
1570 }
1571 AudioPortConfig requestedPortConfig;
1572 requestedPortConfig.portId = portsIt->first;
1573 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001574 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001575 if (matchFlags.getTag() == AudioIoFlags::Tag::input
1576 && source != AudioSource::SYS_RESERVED_INVALID) {
1577 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
1578 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
1579 }
David Lia8675d42023-03-30 21:08:06 +08001580 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1581 created));
Mikhail Naganov61ccb482023-09-08 17:10:16 -07001582 } else if (portConfigIt == mPortConfigs.end() && !flags.has_value()) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001583 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
1584 "and was not created as flags are not specified",
1585 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
1586 return BAD_VALUE;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001587 } else {
David Lia8675d42023-03-30 21:08:06 +08001588 AudioPortConfig requestedPortConfig = portConfigIt->second;
1589 if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
1590 AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
1591 if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
1592 source != AudioSource::SYS_RESERVED_INVALID) {
1593 mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
1594 }
1595 }
1596
1597 if (requestedPortConfig != portConfigIt->second) {
1598 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1599 created));
1600 } else {
1601 *created = false;
1602 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001603 }
1604 *portConfig = portConfigIt->second;
1605 return OK;
1606}
1607
1608status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001609 const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
1610 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001611 using Tag = AudioPortExt::Tag;
1612 if (requestedPortConfig.ext.getTag() == Tag::mix) {
1613 if (const auto& p = requestedPortConfig;
1614 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001615 !p.format.has_value()) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001616 ALOGW("%s: provided mix port config is not fully specified: %s",
1617 __func__, p.toString().c_str());
1618 return BAD_VALUE;
1619 }
1620 AudioConfig config;
1621 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001622 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
1623 AudioPortMixExtUseCase::Tag::source ?
1624 requestedPortConfig.ext.get<Tag::mix>().usecase.
1625 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001626 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001627 requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
1628 portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001629 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
1630 return findOrCreatePortConfig(
jiabin9c07faf2023-04-26 22:00:44 +00001631 requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
1632 portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001633 }
1634 ALOGW("%s: unsupported audio port config: %s",
1635 __func__, requestedPortConfig.toString().c_str());
1636 return BAD_VALUE;
1637}
1638
1639DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
1640 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
1641 return std::find_if(mPatches.begin(), mPatches.end(),
1642 [&](const auto& pair) {
1643 const auto& p = pair.second;
1644 std::set<int32_t> patchSrcs(
1645 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
1646 std::set<int32_t> patchSinks(
1647 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
1648 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
1649}
1650
1651DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001652 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1653 return mPorts.find(mDefaultInputPortId);
1654 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1655 return mPorts.find(mDefaultOutputPortId);
1656 }
Mikhail Naganov892f7612023-09-15 18:55:39 -07001657 if (device.address.getTag() != AudioDeviceAddress::id ||
1658 !device.address.get<AudioDeviceAddress::id>().empty()) {
1659 return std::find_if(mPorts.begin(), mPorts.end(),
1660 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
1661 }
1662 // For connection w/o an address, two ports can be found: the template port,
1663 // and a connected port (if exists). Make sure we return the connected port.
1664 DeviceHalAidl::Ports::iterator portIt = mPorts.end();
1665 for (auto it = mPorts.begin(); it != mPorts.end(); ++it) {
1666 if (audioDeviceMatches(device, it->second)) {
1667 if (mConnectedPorts.find(it->first) != mConnectedPorts.end()) {
1668 return it;
1669 } else {
1670 // Will return 'it' if there is no connected port.
1671 portIt = it;
1672 }
1673 }
1674 }
1675 return portIt;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001676}
1677
1678DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001679 const AudioConfig& config, const AudioIoFlags& flags,
1680 const std::set<int32_t>& destinationPortIds) {
Mikhail Naganove93a0862023-03-15 17:06:59 -07001681 auto belongsToProfile = [&config](const AudioProfile& prof) {
1682 return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
1683 (config.base.channelMask.getTag() == AudioChannelLayout::none ||
1684 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
1685 config.base.channelMask) != prof.channelMasks.end()) &&
1686 (config.base.sampleRate == 0 ||
1687 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
1688 config.base.sampleRate) != prof.sampleRates.end());
1689 };
jiabin9c07faf2023-04-26 22:00:44 +00001690 static const std::vector<AudioOutputFlags> kOptionalOutputFlags{AudioOutputFlags::BIT_PERFECT};
1691 int optionalFlags = 0;
1692 auto flagMatches = [&flags, &optionalFlags](const AudioIoFlags& portFlags) {
1693 // Ports should be able to match if the optional flags are not requested.
1694 return portFlags == flags ||
1695 (portFlags.getTag() == AudioIoFlags::Tag::output &&
1696 AudioIoFlags::make<AudioIoFlags::Tag::output>(
1697 portFlags.get<AudioIoFlags::Tag::output>() &
1698 ~optionalFlags) == flags);
1699 };
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001700 auto matcher = [&](const auto& pair) {
1701 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001702 return p.ext.getTag() == AudioPortExt::Tag::mix &&
jiabin9c07faf2023-04-26 22:00:44 +00001703 flagMatches(p.flags) &&
Mikhail Naganov289468a2023-03-29 10:06:15 -07001704 (destinationPortIds.empty() ||
1705 std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
1706 [&](const int32_t destId) { return mRoutingMatrix.count(
1707 std::make_pair(p.id, destId)) != 0; })) &&
Mikhail Naganove93a0862023-03-15 17:06:59 -07001708 (p.profiles.empty() ||
1709 std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
1710 p.profiles.end()); };
jiabin9c07faf2023-04-26 22:00:44 +00001711 auto result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1712 if (result == mPorts.end() && flags.getTag() == AudioIoFlags::Tag::output) {
1713 auto optionalOutputFlagsIt = kOptionalOutputFlags.begin();
1714 while (result == mPorts.end() && optionalOutputFlagsIt != kOptionalOutputFlags.end()) {
1715 if (isBitPositionFlagSet(
1716 flags.get<AudioIoFlags::Tag::output>(), *optionalOutputFlagsIt)) {
1717 // If the flag is set by the request, it must be matched.
1718 ++optionalOutputFlagsIt;
1719 continue;
1720 }
1721 optionalFlags |= makeBitPositionFlagMask(*optionalOutputFlagsIt++);
1722 result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1723 ALOGI("%s: port for config %s, flags %s was not found in the module %s, "
1724 "retried with excluding optional flags %#x", __func__, config.toString().c_str(),
1725 flags.toString().c_str(), mInstance.c_str(), optionalFlags);
1726 }
1727 }
1728 return result;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001729}
1730
1731DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001732 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001733 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001734}
1735
1736DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
jiabin12537fc2023-10-12 17:56:08 +00001737 const std::optional<AudioConfig>& config,
1738 const std::optional<AudioIoFlags>& flags,
1739 int32_t ioHandle) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001740 using Tag = AudioPortExt::Tag;
1741 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
1742 [&](const auto& pair) {
1743 const auto& p = pair.second;
1744 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
Mikhail Naganove592f1c2023-10-05 17:47:01 -07001745 (!p.sampleRate.has_value() || !p.channelMask.has_value() ||
1746 !p.format.has_value() || !p.flags.has_value()),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001747 "%s: stored mix port config is not fully specified: %s",
1748 __func__, p.toString().c_str());
1749 return p.ext.getTag() == Tag::mix &&
jiabin12537fc2023-10-12 17:56:08 +00001750 (!config.has_value() ||
1751 isConfigEqualToPortConfig(config.value(), p)) &&
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001752 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001753 p.ext.template get<Tag::mix>().handle == ioHandle; });
1754}
Mikhail Naganove93a0862023-03-15 17:06:59 -07001755
Mikhail Naganov66907492023-09-11 17:22:03 -07001756bool DeviceHalAidl::isPortHeldByAStream(int32_t portId) {
1757 // It is assumed that mStreams has already been cleaned up.
1758 for (const auto& streamPair : mStreams) {
1759 int32_t patchId = streamPair.second;
1760 auto patchIt = mPatches.find(patchId);
1761 if (patchIt == mPatches.end()) continue;
1762 for (int32_t id : patchIt->second.sourcePortConfigIds) {
1763 auto portConfigIt = mPortConfigs.find(id);
1764 if (portConfigIt != mPortConfigs.end() && portConfigIt->second.portId == portId) {
1765 return true;
1766 }
1767 }
1768 for (int32_t id : patchIt->second.sinkPortConfigIds) {
1769 auto portConfigIt = mPortConfigs.find(id);
1770 if (portConfigIt != mPortConfigs.end() && portConfigIt->second.portId == portId) {
1771 return true;
1772 }
1773 }
1774 }
1775 return false;
1776}
1777
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001778void DeviceHalAidl::resetPatch(int32_t patchId) {
1779 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1780 mPatches.erase(it);
1781 TIME_CHECK();
1782 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1783 ALOGE("%s: error while resetting patch %d: %s",
1784 __func__, patchId, status.getDescription().c_str());
1785 }
1786 return;
1787 }
1788 ALOGE("%s: patch id %d not found", __func__, patchId);
1789}
1790
1791void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1792 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1793 mPortConfigs.erase(it);
1794 TIME_CHECK();
1795 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1796 !status.isOk()) {
1797 ALOGE("%s: error while resetting port config %d: %s",
1798 __func__, portConfigId, status.getDescription().c_str());
1799 }
1800 return;
1801 }
1802 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1803}
1804
Mikhail Naganove93a0862023-03-15 17:06:59 -07001805void DeviceHalAidl::resetUnusedPatches() {
1806 // Since patches can be created independently of streams via 'createAudioPatch',
1807 // here we only clean up patches for released streams.
1808 for (auto it = mStreams.begin(); it != mStreams.end(); ) {
1809 if (auto streamSp = it->first.promote(); streamSp) {
1810 ++it;
1811 } else {
1812 resetPatch(it->second);
1813 it = mStreams.erase(it);
1814 }
1815 }
1816}
1817
1818void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
1819 resetUnusedPatches();
1820 resetUnusedPortConfigs();
1821}
1822
1823void DeviceHalAidl::resetUnusedPortConfigs() {
1824 // The assumption is that port configs are used to create patches
1825 // (or to open streams, but that involves creation of patches, too). Thus,
1826 // orphaned port configs can and should be reset.
Mikhail Naganov66907492023-09-11 17:22:03 -07001827 std::map<int32_t, int32_t /*portID*/> portConfigIds;
Mikhail Naganove93a0862023-03-15 17:06:59 -07001828 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
1829 std::inserter(portConfigIds, portConfigIds.end()),
Mikhail Naganov66907492023-09-11 17:22:03 -07001830 [](const auto& pcPair) { return std::make_pair(pcPair.first, pcPair.second.portId); });
Mikhail Naganove93a0862023-03-15 17:06:59 -07001831 for (const auto& p : mPatches) {
1832 for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
1833 for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
1834 }
jiabin9c07faf2023-04-26 22:00:44 +00001835 for (int32_t id : mInitialPortConfigIds) {
1836 portConfigIds.erase(id);
1837 }
Mikhail Naganov66907492023-09-11 17:22:03 -07001838 std::set<int32_t> retryDeviceDisconnection;
1839 for (const auto& portConfigAndIdPair : portConfigIds) {
1840 resetPortConfig(portConfigAndIdPair.first);
Mikhail Naganov892f7612023-09-15 18:55:39 -07001841 if (const auto it = mConnectedPorts.find(portConfigAndIdPair.second);
1842 it != mConnectedPorts.end() && it->second) {
Mikhail Naganov66907492023-09-11 17:22:03 -07001843 retryDeviceDisconnection.insert(portConfigAndIdPair.second);
1844 }
1845 }
1846 for (int32_t portId : retryDeviceDisconnection) {
1847 if (!isPortHeldByAStream(portId)) {
1848 TIME_CHECK();
1849 if (auto status = mModule->disconnectExternalDevice(portId); status.isOk()) {
1850 mPorts.erase(portId);
Mikhail Naganov892f7612023-09-15 18:55:39 -07001851 mConnectedPorts.erase(portId);
Mikhail Naganov66907492023-09-11 17:22:03 -07001852 ALOGD("%s: executed postponed external device disconnection for port ID %d",
1853 __func__, portId);
1854 }
1855 }
1856 }
1857 if (!retryDeviceDisconnection.empty()) {
1858 updateRoutes();
1859 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001860}
1861
Mikhail Naganov289468a2023-03-29 10:06:15 -07001862status_t DeviceHalAidl::updateRoutes() {
1863 TIME_CHECK();
Mikhail Naganov289468a2023-03-29 10:06:15 -07001864 RETURN_STATUS_IF_ERROR(
Mikhail Naganovf83b9742023-04-24 13:06:04 -07001865 statusTFromBinderStatus(mModule->getAudioRoutes(&mRoutes)));
1866 ALOGW_IF(mRoutes.empty(), "%s: module %s returned an empty list of audio routes",
Mikhail Naganov289468a2023-03-29 10:06:15 -07001867 __func__, mInstance.c_str());
1868 mRoutingMatrix.clear();
Mikhail Naganovf83b9742023-04-24 13:06:04 -07001869 for (const auto& r : mRoutes) {
Mikhail Naganov289468a2023-03-29 10:06:15 -07001870 for (auto portId : r.sourcePortIds) {
1871 mRoutingMatrix.emplace(r.sinkPortId, portId);
1872 mRoutingMatrix.emplace(portId, r.sinkPortId);
1873 }
1874 }
1875 return OK;
1876}
1877
jiabin12537fc2023-10-12 17:56:08 +00001878status_t DeviceHalAidl::getAudioPort(int32_t portId, AudioPort* port) {
1879 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
1880 TIME_CHECK();
1881 if (!mModule) {
1882 return NO_INIT;
1883 }
1884 const status_t status = statusTFromBinderStatus(mModule->getAudioPort(portId, port));
1885 if (status == OK) {
1886 auto portIt = mPorts.find(portId);
1887 if (portIt != mPorts.end()) {
1888 portIt->second = *port;
1889 } else {
1890 ALOGW("%s, port(%d) returned successfully from the HAL but not it is not cached",
1891 __func__, portId);
1892 }
1893 }
1894 return status;
1895}
1896
Mikhail Naganovdfd594e2023-02-08 16:59:41 -08001897void DeviceHalAidl::clearCallbacks(void* cookie) {
1898 std::lock_guard l(mLock);
1899 mCallbacks.erase(cookie);
1900}
1901
1902sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1903 return getCallbackImpl(cookie, &Callbacks::out);
1904}
1905
1906void DeviceHalAidl::setStreamOutCallback(
1907 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1908 setCallbackImpl(cookie, &Callbacks::out, cb);
1909}
1910
1911sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1912 void* cookie) {
1913 return getCallbackImpl(cookie, &Callbacks::event);
1914}
1915
1916void DeviceHalAidl::setStreamOutEventCallback(
1917 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1918 setCallbackImpl(cookie, &Callbacks::event, cb);
1919}
1920
1921sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1922 void* cookie) {
1923 return getCallbackImpl(cookie, &Callbacks::latency);
1924}
1925
1926void DeviceHalAidl::setStreamOutLatencyModeCallback(
1927 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1928 setCallbackImpl(cookie, &Callbacks::latency, cb);
1929}
1930
1931template<class C>
1932sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1933 std::lock_guard l(mLock);
1934 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1935 return ((it->second).*field).promote();
1936 }
1937 return nullptr;
1938}
1939template<class C>
1940void DeviceHalAidl::setCallbackImpl(
1941 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1942 std::lock_guard l(mLock);
1943 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1944 (it->second).*field = cb;
1945 }
1946}
1947
Mikhail Naganov31d46652023-01-10 18:29:25 +00001948} // namespace android