blob: 31572f7d099333b11eb78419cdfe8dee0f02d742 [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"
Vlad Popa03bd5bc2023-01-17 16:16:51 +010018// #define LOG_NDEBUG 0
Shunkai Yao51202502022-12-12 06:11:46 +000019
Mikhail Naganovf56ce782023-01-25 11:29:11 -080020#include <algorithm>
21#include <forward_list>
22
Mikhail Naganovb0c55252023-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 Naganovbfbb75b2023-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 Naganov8bd806e2023-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 Naganov27382bb2023-04-27 18:14:15 -070039using aidl::android::media::audio::common::Boolean;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -070040using aidl::android::media::audio::common::AudioChannelLayout;
Mikhail Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovb1ddbb02023-03-15 17:06:59 -070046using aidl::android::media::audio::common::AudioFormatType;
Mikhail Naganov8bd806e2023-01-30 12:33:18 -080047using aidl::android::media::audio::common::AudioInputFlags;
Mikhail Naganovf56ce782023-01-25 11:29:11 -080048using aidl::android::media::audio::common::AudioIoFlags;
Mikhail Naganovb0c55252023-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 Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovb1ddbb02023-03-15 17:06:59 -070061using aidl::android::media::audio::common::AudioProfile;
Mikhail Naganovf56ce782023-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 Naganovb1ddbb02023-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 Naganovf56ce782023-01-25 11:29:11 -080072using aidl::android::hardware::audio::common::RecordTrackMetadata;
73using aidl::android::hardware::audio::core::AudioPatch;
Mikhail Naganovecfafb72023-03-29 10:06:15 -070074using aidl::android::hardware::audio::core::AudioRoute;
Mikhail Naganov27382bb2023-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 Naganovb1ddbb02023-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 Naganovf56ce782023-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 Naganovf56ce782023-01-25 11:29:11 -0800110}
111
Mikhail Naganov2d814892023-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;
121 return cpp;
122}
123
Mikhail Naganovffd97712023-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 Naganovf56ce782023-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 Naganovffd97712023-05-03 17:45:36 -0700140 : ConversionHelperAidl("DeviceHalAidl"),
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700141 mInstance(instance), mModule(module), mVendorExt(vext),
Mikhail Naganov27382bb2023-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 Naganovffd97712023-05-03 17:45:36 -0700146}
147
Mikhail Naganov2d814892023-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 Naganov2d814892023-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 Naganovffd97712023-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 Naganovf56ce782023-01-25 11:29:11 -0800182 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000183 if (mModule == nullptr) return NO_INIT;
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800184 std::vector<AudioPort> ports;
Mikhail Naganov2d814892023-04-24 13:06:04 -0700185 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
Mikhail Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovecfafb72023-03-29 10:06:15 -0700205 RETURN_STATUS_IF_ERROR(updateRoutes());
Mikhail Naganovf56ce782023-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); });
jiabin2248fa12023-04-27 22:04:16 +0000212 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
213 std::inserter(mInitialPortConfigIds, mInitialPortConfigIds.end()),
214 [](const auto& pcPair) { return pcPair.first; });
Mikhail Naganovf56ce782023-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 Naganovffd97712023-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 Naganovffd97712023-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 Naganov27382bb2023-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 Naganov27382bb2023-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 Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganov8bd806e2023-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 Naganovb1ddbb02023-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 Naganovb1ddbb02023-03-15 17:06:59 -0700372 &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov8bd806e2023-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 Naganovf56ce782023-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 Naganov8bd806e2023-01-30 12:33:18 -0800382 Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
Mikhail Naganovb1ddbb02023-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());
jiabin2248fa12023-04-27 22:04:16 +0000388 resetUnusedPatchesAndPortConfigs();
Mikhail Naganovf56ce782023-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;
jiabin2248fa12023-04-27 22:04:16 +0000394 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, aidlConfig,
395 &devicePortConfig, &created));
Mikhail Naganovf56ce782023-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 Naganovecfafb72023-03-29 10:06:15 -0700400 std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800401 if (created) {
402 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
403 }
404 setConfigFromPortConfig(aidlConfig, *mixPortConfig);
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800405 if (isInput) {
406 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700407 {devicePortConfig.id}, {mixPortConfig->id}, aidlPatch, &created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800408 } else {
409 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700410 {mixPortConfig->id}, {devicePortConfig.id}, aidlPatch, &created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800411 }
412 if (created) {
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700413 cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, aidlPatch->id);
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800414 }
415 if (aidlConfig->frameCount <= 0) {
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700416 aidlConfig->frameCount = aidlPatch->minimumStreamBufferSizeFrames;
Mikhail Naganovf56ce782023-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 Naganovb0c55252023-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 Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovf56ce782023-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 Naganovb1ddbb02023-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 Naganovb1ddbb02023-03-15 17:06:59 -0700565 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800566 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
567 args.portConfigId = mixPortConfig.id;
Mikhail Naganovb0c55252023-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 Naganovf56ce782023-01-25 11:29:11 -0800579 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovb0c55252023-02-08 16:59:41 -0800580 args.eventCallback = eventCb;
Mikhail Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovb1ddbb02023-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 Naganovb1ddbb02023-03-15 17:06:59 -0700591 mStreams.insert(std::pair(*outStream, aidlPatch.id));
Mikhail Naganovb0c55252023-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 Naganovf56ce782023-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 Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovf56ce782023-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 Naganovb1ddbb02023-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 Naganovb1ddbb02023-03-15 17:06:59 -0700630 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovb1ddbb02023-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 Naganovb1ddbb02023-03-15 17:06:59 -0700652 mStreams.insert(std::pair(*inStream, aidlPatch.id));
Mikhail Naganovf56ce782023-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 Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovf56ce782023-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 Naganovf56ce782023-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 Naganovf56ce782023-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 Naganovf56ce782023-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 Naganov8bd806e2023-01-30 12:33:18 -0800721 __func__, ::android::internal::ToString(aidlSources).c_str(),
722 ::android::internal::ToString(aidlSinks).c_str());
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800723 auto fillPortConfigs = [&](
Mikhail Naganovecfafb72023-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 Naganovf56ce782023-01-25 11:29:11 -0800727 for (const auto& s : configs) {
728 AudioPortConfig portConfig;
729 bool created = false;
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700730 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
731 s, destinationPortIds, &portConfig, &created));
Mikhail Naganovf56ce782023-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 Naganovecfafb72023-03-29 10:06:15 -0700736 if (portIds != nullptr) {
737 portIds->insert(portConfig.portId);
738 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800739 }
740 return OK;
741 };
Mikhail Naganovecfafb72023-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 Naganovf56ce782023-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 Naganovf56ce782023-01-25 11:29:11 -0800769 }
770 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000771 return OK;
772}
773
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800774status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov8bd806e2023-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 Naganovf56ce782023-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 Naganovb1ddbb02023-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 Naganovb1ddbb02023-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
839status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
840 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
841 TIME_CHECK();
842 if (!mModule) return NO_INIT;
843 if (config == nullptr) {
844 return BAD_VALUE;
845 }
846 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
847 config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
848 AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
849 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
850 *config, isInput, 0 /*portId*/));
851 AudioPortConfig portConfig;
852 bool created = false;
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700853 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
854 requestedPortConfig, std::set<int32_t>(), &portConfig, &created));
Shunkai Yao51202502022-12-12 06:11:46 +0000855 return OK;
856}
857
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800858MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
859 if (mMicrophones.status == Microphones::Status::UNKNOWN) {
860 TIME_CHECK();
861 std::vector<MicrophoneInfo> aidlInfo;
862 status_t status = statusTFromBinderStatus(mModule->getMicrophones(&aidlInfo));
863 if (status == OK) {
864 mMicrophones.status = Microphones::Status::QUERIED;
865 mMicrophones.info = std::move(aidlInfo);
866 } else if (status == INVALID_OPERATION) {
867 mMicrophones.status = Microphones::Status::NOT_SUPPORTED;
868 } else {
869 ALOGE("%s: Unexpected status from 'IModule.getMicrophones': %d", __func__, status);
870 return {};
871 }
872 }
873 if (mMicrophones.status == Microphones::Status::QUERIED) {
874 return &mMicrophones.info;
875 }
876 return {}; // NOT_SUPPORTED
877}
878
Shunkai Yao51202502022-12-12 06:11:46 +0000879status_t DeviceHalAidl::getMicrophones(
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800880 std::vector<audio_microphone_characteristic_t>* microphones) {
881 if (!microphones) {
882 return BAD_VALUE;
883 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000884 TIME_CHECK();
885 if (!mModule) return NO_INIT;
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800886 auto staticInfo = getMicrophoneInfo();
887 if (!staticInfo) return INVALID_OPERATION;
888 std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
889 emptyDynamicInfo.reserve(staticInfo->size());
890 std::transform(staticInfo->begin(), staticInfo->end(), std::back_inserter(emptyDynamicInfo),
891 [](const auto& info) { return MicrophoneDynamicInfo{ .id = info.id }; });
892 *microphones = VALUE_OR_RETURN_STATUS(
893 ::aidl::android::convertContainers<std::vector<audio_microphone_characteristic_t>>(
894 *staticInfo, emptyDynamicInfo,
895 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t)
896 );
Shunkai Yao51202502022-12-12 06:11:46 +0000897 return OK;
898}
899
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700900status_t DeviceHalAidl::addDeviceEffect(
901 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
902 TIME_CHECK();
903 if (!mModule) return NO_INIT;
Shunkai Yao51202502022-12-12 06:11:46 +0000904 if (!effect) {
905 return BAD_VALUE;
906 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700907 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
908 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
909 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
910 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
911 *device, isInput, 0));
912 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
913 ALOGE("%s: provided port config is not a device port config: %s",
914 __func__, requestedPortConfig.toString().c_str());
915 return BAD_VALUE;
916 }
917 AudioPortConfig devicePortConfig;
918 bool created;
919 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
920 requestedPortConfig, {} /*destinationPortIds*/, &devicePortConfig, &created));
921 Cleanups cleanups;
922 if (created) {
923 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
924 }
925 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
926 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->addDeviceEffect(
927 devicePortConfig.id, aidlEffect->getIEffect())));
928 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000929 return OK;
930}
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700931status_t DeviceHalAidl::removeDeviceEffect(
932 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
933 TIME_CHECK();
934 if (!mModule) return NO_INIT;
Shunkai Yao51202502022-12-12 06:11:46 +0000935 if (!effect) {
936 return BAD_VALUE;
937 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700938 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
939 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
940 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
941 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
942 *device, isInput, 0));
943 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
944 ALOGE("%s: provided port config is not a device port config: %s",
945 __func__, requestedPortConfig.toString().c_str());
946 return BAD_VALUE;
947 }
948 auto existingPortConfigIt = findPortConfig(
949 requestedPortConfig.ext.get<AudioPortExt::Tag::device>().device);
950 if (existingPortConfigIt == mPortConfigs.end()) {
951 ALOGE("%s: could not find a configured device port for the config %s",
952 __func__, requestedPortConfig.toString().c_str());
953 return BAD_VALUE;
954 }
955 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
956 return statusTFromBinderStatus(mModule->removeDeviceEffect(
957 existingPortConfigIt->first, aidlEffect->getIEffect()));
Shunkai Yao51202502022-12-12 06:11:46 +0000958}
959
960status_t DeviceHalAidl::getMmapPolicyInfos(
David Li9cf5e622023-03-21 00:51:10 +0800961 media::audio::common::AudioMMapPolicyType policyType,
962 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000963 TIME_CHECK();
Mikhail Naganovbfbb75b2023-04-21 18:48:16 -0700964 AudioMMapPolicyType mmapPolicyType = VALUE_OR_RETURN_STATUS(
965 cpp2ndk_AudioMMapPolicyType(policyType));
David Li9cf5e622023-03-21 00:51:10 +0800966
967 std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
968
969 if (status_t status = statusTFromBinderStatus(
970 mModule->getMmapPolicyInfos(mmapPolicyType, &mmapPolicyInfos)); status != OK) {
971 return status;
972 }
973
974 *policyInfos = VALUE_OR_RETURN_STATUS(
975 convertContainer<std::vector<media::audio::common::AudioMMapPolicyInfo>>(
976 mmapPolicyInfos, ndk2cpp_AudioMMapPolicyInfo));
Shunkai Yao51202502022-12-12 06:11:46 +0000977 return OK;
978}
979
980int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000981 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800982 int32_t mixerBurstCount = 0;
983 if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
984 return mixerBurstCount;
985 }
986 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000987}
988
989int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000990 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800991 int32_t hardwareBurstMinUsec = 0;
992 if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
993 return hardwareBurstMinUsec;
994 }
995 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000996}
997
998error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000999 TIME_CHECK();
Mikhail Naganov08a62ab2023-03-14 17:11:51 -07001000 if (!mModule) return NO_INIT;
1001 int32_t aidlHwAvSync;
1002 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
1003 return VALUE_OR_RETURN_STATUS(
1004 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +00001005}
1006
Mikhail Naganovfab697c2023-01-11 19:33:13 +00001007status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
1008 TIME_CHECK();
1009 if (!mModule) return NO_INIT;
1010 return mModule->dump(fd, Args(args).args(), args.size());
David Li9cf5e622023-03-21 00:51:10 +08001011}
Shunkai Yao51202502022-12-12 06:11:46 +00001012
Eric Laurent8ed6d792023-06-29 11:44:54 +02001013status_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
Mikhail Naganov31d46652023-01-10 18:29:25 +00001014 TIME_CHECK();
Mikhail Naganov3ac95c92023-04-12 13:14:30 -07001015 if (!mModule) return NO_INIT;
1016 if (supports == nullptr) {
1017 return BAD_VALUE;
1018 }
1019 return statusTFromBinderStatus(mModule->supportsVariableLatency(supports));
Shunkai Yao51202502022-12-12 06:11:46 +00001020}
Mikhail Naganov31d46652023-01-10 18:29:25 +00001021
Vlad Popa03bd5bc2023-01-17 16:16:51 +01001022status_t DeviceHalAidl::getSoundDoseInterface(const std::string& module,
1023 ::ndk::SpAIBinder* soundDoseBinder) {
1024 TIME_CHECK();
1025 if (!mModule) return NO_INIT;
1026 if (mSoundDose == nullptr) {
1027 ndk::ScopedAStatus status = mModule->getSoundDose(&mSoundDose);
1028 if (!status.isOk()) {
1029 ALOGE("%s failed to return the sound dose interface for module %s: %s",
1030 __func__,
1031 module.c_str(),
1032 status.getDescription().c_str());
1033 return BAD_VALUE;
1034 }
1035 }
Vlad Popae1f33902023-10-30 19:48:25 -07001036
1037 if (mSoundDose == nullptr) {
1038 ALOGE("%s failed to return the sound dose interface for module %s: not implemented",
1039 __func__,
1040 module.c_str());
1041 return NO_INIT;
1042 }
1043
Vlad Popa03bd5bc2023-01-17 16:16:51 +01001044 *soundDoseBinder = mSoundDose->asBinder();
1045 ALOGI("%s using audio AIDL HAL sound dose interface", __func__);
1046
1047 return OK;
1048}
1049
jiabinc0048632023-04-27 22:04:31 +00001050status_t DeviceHalAidl::prepareToDisconnectExternalDevice(const struct audio_port_v7* port) {
1051 // There is not AIDL API defined for `prepareToDisconnectExternalDevice`.
1052 // Call `setConnectedState` instead.
1053 // TODO(b/279824103): call prepareToDisconnectExternalDevice when it is added.
Mikhail Naganov66907492023-09-11 17:22:03 -07001054 if (const status_t status = setConnectedState(port, false /*connected*/); status == NO_ERROR) {
jiabinc0048632023-04-27 22:04:31 +00001055 mDeviceDisconnectionNotified.insert(port->id);
1056 }
Mikhail Naganov66907492023-09-11 17:22:03 -07001057 // Return that there was no error as otherwise the disconnection procedure will not be
1058 // considered complete for upper layers, and 'setConnectedState' will not be called again.
1059 return NO_ERROR;
jiabinc0048632023-04-27 22:04:31 +00001060}
1061
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001062status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
1063 TIME_CHECK();
1064 if (!mModule) return NO_INIT;
1065 if (port == nullptr) {
1066 return BAD_VALUE;
1067 }
jiabinc0048632023-04-27 22:04:31 +00001068 if (!connected && mDeviceDisconnectionNotified.erase(port->id) > 0) {
1069 // For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
1070 // and then call `setConnectedState`. However, there is no API for
1071 // `prepareToDisconnectExternalDevice` yet. In that case, `setConnectedState` will be
1072 // called when calling `prepareToDisconnectExternalDevice`. Do not call to the HAL if
1073 // previous call is successful. Also remove the cache here to avoid a large cache after
1074 // a long run.
1075 return NO_ERROR;
1076 }
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001077 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
1078 ::aidl::android::AudioPortDirection::INPUT;
1079 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
1080 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
1081 if (aidlPort.ext.getTag() != AudioPortExt::device) {
1082 ALOGE("%s: provided port is not a device port (module %s): %s",
1083 __func__, mInstance.c_str(), aidlPort.toString().c_str());
1084 return BAD_VALUE;
1085 }
1086 if (connected) {
1087 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1088 // Reset the device address to find the "template" port.
1089 matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
1090 auto portsIt = findPort(matchDevice);
1091 if (portsIt == mPorts.end()) {
Mikhail Naganov69557132023-09-07 15:29:01 -07001092 // Since 'setConnectedState' is called for all modules, it is normal when the device
1093 // port not found in every one of them.
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001094 return BAD_VALUE;
Mikhail Naganov02038012023-09-08 12:38:14 -07001095 } else {
1096 ALOGD("%s: device port for device %s found in the module %s",
1097 __func__, matchDevice.toString().c_str(), mInstance.c_str());
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001098 }
Mikhail Naganov66907492023-09-11 17:22:03 -07001099 resetUnusedPatchesAndPortConfigs();
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001100 // Use the ID of the "template" port, use all the information from the provided port.
1101 aidlPort.id = portsIt->first;
1102 AudioPort connectedPort;
1103 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
1104 aidlPort, &connectedPort)));
1105 const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
1106 LOG_ALWAYS_FATAL_IF(!inserted,
1107 "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
1108 __func__, mInstance.c_str(), connectedPort.toString().c_str(),
1109 it->second.toString().c_str());
Mikhail Naganov892f7612023-09-15 18:55:39 -07001110 mConnectedPorts[connectedPort.id] = false;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001111 } else { // !connected
1112 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1113 auto portsIt = findPort(matchDevice);
1114 if (portsIt == mPorts.end()) {
Mikhail Naganov02038012023-09-08 12:38:14 -07001115 // Since 'setConnectedState' is called for all modules, it is normal when the device
1116 // port not found in every one of them.
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001117 return BAD_VALUE;
Mikhail Naganov02038012023-09-08 12:38:14 -07001118 } else {
1119 ALOGD("%s: device port for device %s found in the module %s",
1120 __func__, matchDevice.toString().c_str(), mInstance.c_str());
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001121 }
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001122 resetUnusedPatchesAndPortConfigs();
Mikhail Naganov66907492023-09-11 17:22:03 -07001123 // Streams are closed by AudioFlinger independently from device disconnections.
1124 // It is possible that the stream has not been closed yet.
1125 const int32_t portId = portsIt->second.id;
1126 if (!isPortHeldByAStream(portId)) {
1127 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1128 mModule->disconnectExternalDevice(portId)));
1129 mPorts.erase(portsIt);
Mikhail Naganov892f7612023-09-15 18:55:39 -07001130 mConnectedPorts.erase(portId);
Mikhail Naganov66907492023-09-11 17:22:03 -07001131 } else {
1132 ALOGD("%s: since device port ID %d is used by a stream, "
1133 "external device disconnection postponed", __func__, portId);
Mikhail Naganov892f7612023-09-15 18:55:39 -07001134 mConnectedPorts[portId] = true;
Mikhail Naganov66907492023-09-11 17:22:03 -07001135 }
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001136 }
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001137 return updateRoutes();
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001138}
1139
1140status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
1141 TIME_CHECK();
1142 if (!mModule) return NO_INIT;
Mikhail Naganov66907492023-09-11 17:22:03 -07001143 resetUnusedPatchesAndPortConfigs();
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001144 ModuleDebug debug{ .simulateDeviceConnections = enabled };
1145 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
1146 // This is important to log as it affects HAL behavior.
1147 if (status == OK) {
1148 ALOGI("%s: set enabled: %d", __func__, enabled);
1149 } else {
1150 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
1151 }
1152 return status;
1153}
1154
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001155bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
1156 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1157 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1158}
1159
1160bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
1161 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1162 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1163 return p.portId == mDefaultInputPortId;
1164 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1165 return p.portId == mDefaultOutputPortId;
1166 }
1167 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1168}
1169
David Lia8f1e582023-03-30 21:08:06 +08001170status_t DeviceHalAidl::createOrUpdatePortConfig(
1171 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool* created) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001172 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001173 AudioPortConfig appliedPortConfig;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001174 bool applied = false;
1175 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001176 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001177 if (!applied) {
1178 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001179 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001180 if (!applied) {
1181 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001182 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001183 return NO_INIT;
1184 }
1185 }
David Lia8f1e582023-03-30 21:08:06 +08001186
1187 int32_t id = appliedPortConfig.id;
1188 if (requestedPortConfig.id != 0 && requestedPortConfig.id != id) {
1189 LOG_ALWAYS_FATAL("%s: requested port config id %d changed to %d", __func__,
1190 requestedPortConfig.id, id);
1191 }
1192
1193 auto [it, inserted] = mPortConfigs.insert_or_assign(std::move(id),
1194 std::move(appliedPortConfig));
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001195 *result = it;
David Lia8f1e582023-03-30 21:08:06 +08001196 *created = inserted;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001197 return OK;
1198}
1199
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001200status_t DeviceHalAidl::filterAndRetrieveBtA2dpParameters(
1201 AudioParameter &keys, AudioParameter *result) {
1202 TIME_CHECK();
1203 if (String8 key = String8(AudioParameter::keyReconfigA2dpSupported); keys.containsKey(key)) {
1204 keys.remove(key);
1205 bool supports;
1206 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1207 mBluetoothA2dp->supportsOffloadReconfiguration(&supports)));
1208 result->addInt(key, supports ? 1 : 0);
1209 }
1210 return OK;
1211}
1212
Mikhail Naganov27382bb2023-04-27 18:14:15 -07001213status_t DeviceHalAidl::filterAndUpdateBtA2dpParameters(AudioParameter &parameters) {
1214 TIME_CHECK();
1215 std::optional<bool> a2dpEnabled;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001216 std::optional<std::vector<VendorParameter>> reconfigureOffload;
Mikhail Naganov27382bb2023-04-27 18:14:15 -07001217 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1218 parameters, String8(AudioParameter::keyBtA2dpSuspended),
1219 [&a2dpEnabled](const String8& trueOrFalse) {
1220 if (trueOrFalse == AudioParameter::valueTrue) {
1221 a2dpEnabled = false; // 'suspended' == true
1222 return OK;
1223 } else if (trueOrFalse == AudioParameter::valueFalse) {
1224 a2dpEnabled = true; // 'suspended' == false
1225 return OK;
1226 }
1227 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1228 AudioParameter::keyBtA2dpSuspended, trueOrFalse.c_str());
1229 return BAD_VALUE;
1230 }));
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001231 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1232 parameters, String8(AudioParameter::keyReconfigA2dp),
1233 [&](const String8& value) -> status_t {
1234 if (mVendorExt != nullptr) {
1235 std::vector<VendorParameter> result;
1236 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1237 mVendorExt->parseBluetoothA2dpReconfigureOffload(
1238 std::string(value.c_str()), &result)));
1239 reconfigureOffload = std::move(result);
1240 } else {
1241 reconfigureOffload = std::vector<VendorParameter>();
1242 }
1243 return OK;
1244 }));
Mikhail Naganov27382bb2023-04-27 18:14:15 -07001245 if (mBluetoothA2dp != nullptr && a2dpEnabled.has_value()) {
1246 return statusTFromBinderStatus(mBluetoothA2dp->setEnabled(a2dpEnabled.value()));
1247 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001248 if (mBluetoothA2dp != nullptr && reconfigureOffload.has_value()) {
1249 return statusTFromBinderStatus(mBluetoothA2dp->reconfigureOffload(
1250 reconfigureOffload.value()));
1251 }
Mikhail Naganov27382bb2023-04-27 18:14:15 -07001252 return OK;
1253}
1254
1255status_t DeviceHalAidl::filterAndUpdateBtHfpParameters(AudioParameter &parameters) {
1256 TIME_CHECK();
1257 IBluetooth::HfpConfig hfpConfig;
1258 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1259 parameters, String8(AudioParameter::keyBtHfpEnable),
1260 [&hfpConfig](const String8& trueOrFalse) {
1261 if (trueOrFalse == AudioParameter::valueTrue) {
1262 hfpConfig.isEnabled = Boolean{ .value = true };
1263 return OK;
1264 } else if (trueOrFalse == AudioParameter::valueFalse) {
1265 hfpConfig.isEnabled = Boolean{ .value = false };
1266 return OK;
1267 }
1268 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1269 AudioParameter::keyBtHfpEnable, trueOrFalse.c_str());
1270 return BAD_VALUE;
1271 }));
1272 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1273 parameters, String8(AudioParameter::keyBtHfpSamplingRate),
1274 [&hfpConfig](int sampleRate) {
1275 return sampleRate > 0 ?
1276 hfpConfig.sampleRate = Int{ .value = sampleRate }, OK : BAD_VALUE;
1277 }));
1278 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1279 parameters, String8(AudioParameter::keyBtHfpVolume),
1280 [&hfpConfig](int volume0to15) {
1281 if (volume0to15 >= 0 && volume0to15 <= 15) {
1282 hfpConfig.volume = Float{ .value = volume0to15 / 15.0f };
1283 return OK;
1284 }
1285 return BAD_VALUE;
1286 }));
1287 if (mBluetooth != nullptr && hfpConfig != IBluetooth::HfpConfig{}) {
1288 IBluetooth::HfpConfig newHfpConfig;
1289 return statusTFromBinderStatus(mBluetooth->setHfpConfig(hfpConfig, &newHfpConfig));
1290 }
1291 return OK;
1292}
1293
1294status_t DeviceHalAidl::filterAndUpdateBtLeParameters(AudioParameter &parameters) {
1295 TIME_CHECK();
1296 std::optional<bool> leEnabled;
1297 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1298 parameters, String8(AudioParameter::keyBtLeSuspended),
1299 [&leEnabled](const String8& trueOrFalse) {
1300 if (trueOrFalse == AudioParameter::valueTrue) {
1301 leEnabled = false; // 'suspended' == true
1302 return OK;
1303 } else if (trueOrFalse == AudioParameter::valueFalse) {
1304 leEnabled = true; // 'suspended' == false
1305 return OK;
1306 }
1307 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1308 AudioParameter::keyBtLeSuspended, trueOrFalse.c_str());
1309 return BAD_VALUE;
1310 }));
1311 if (mBluetoothLe != nullptr && leEnabled.has_value()) {
1312 return statusTFromBinderStatus(mBluetoothLe->setEnabled(leEnabled.value()));
1313 }
1314 return OK;
1315}
1316
1317status_t DeviceHalAidl::filterAndUpdateBtScoParameters(AudioParameter &parameters) {
1318 TIME_CHECK();
1319 IBluetooth::ScoConfig scoConfig;
1320 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1321 parameters, String8(AudioParameter::keyBtSco),
1322 [&scoConfig](const String8& onOrOff) {
1323 if (onOrOff == AudioParameter::valueOn) {
1324 scoConfig.isEnabled = Boolean{ .value = true };
1325 return OK;
1326 } else if (onOrOff == AudioParameter::valueOff) {
1327 scoConfig.isEnabled = Boolean{ .value = false };
1328 return OK;
1329 }
1330 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1331 AudioParameter::keyBtSco, onOrOff.c_str());
1332 return BAD_VALUE;
1333 }));
1334 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1335 parameters, String8(AudioParameter::keyBtScoHeadsetName),
1336 [&scoConfig](const String8& name) {
1337 scoConfig.debugName = name;
1338 return OK;
1339 }));
1340 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1341 parameters, String8(AudioParameter::keyBtNrec),
1342 [&scoConfig](const String8& onOrOff) {
1343 if (onOrOff == AudioParameter::valueOn) {
1344 scoConfig.isNrecEnabled = Boolean{ .value = true };
1345 return OK;
1346 } else if (onOrOff == AudioParameter::valueOff) {
1347 scoConfig.isNrecEnabled = Boolean{ .value = false };
1348 return OK;
1349 }
1350 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1351 AudioParameter::keyBtNrec, onOrOff.c_str());
1352 return BAD_VALUE;
1353 }));
1354 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1355 parameters, String8(AudioParameter::keyBtScoWb),
1356 [&scoConfig](const String8& onOrOff) {
1357 if (onOrOff == AudioParameter::valueOn) {
1358 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO_WB;
1359 return OK;
1360 } else if (onOrOff == AudioParameter::valueOff) {
1361 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO;
1362 return OK;
1363 }
1364 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1365 AudioParameter::keyBtScoWb, onOrOff.c_str());
1366 return BAD_VALUE;
1367 }));
1368 if (mBluetooth != nullptr && scoConfig != IBluetooth::ScoConfig{}) {
1369 IBluetooth::ScoConfig newScoConfig;
1370 return statusTFromBinderStatus(mBluetooth->setScoConfig(scoConfig, &newScoConfig));
1371 }
1372 return OK;
1373}
1374
Mikhail Naganove92c34b2023-05-31 14:24:48 -07001375status_t DeviceHalAidl::filterAndUpdateScreenParameters(AudioParameter &parameters) {
1376 TIME_CHECK();
1377 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1378 parameters, String8(AudioParameter::keyScreenState),
1379 [&](const String8& onOrOff) -> status_t {
1380 std::optional<bool> isTurnedOn;
1381 if (onOrOff == AudioParameter::valueOn) {
1382 isTurnedOn = true;
1383 } else if (onOrOff == AudioParameter::valueOff) {
1384 isTurnedOn = false;
1385 }
1386 if (!isTurnedOn.has_value()) {
1387 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1388 AudioParameter::keyScreenState, onOrOff.c_str());
1389 return BAD_VALUE;
1390 }
1391 return statusTFromBinderStatus(
1392 mModule->updateScreenState(isTurnedOn.value()));
1393 }));
1394 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1395 parameters, String8(AudioParameter::keyScreenRotation),
1396 [&](int rotationDegrees) -> status_t {
1397 IModule::ScreenRotation rotation;
1398 switch (rotationDegrees) {
1399 case 0: rotation = IModule::ScreenRotation::DEG_0; break;
1400 case 90: rotation = IModule::ScreenRotation::DEG_90; break;
1401 case 180: rotation = IModule::ScreenRotation::DEG_180; break;
1402 case 270: rotation = IModule::ScreenRotation::DEG_270; break;
1403 default:
1404 ALOGE("setParameters: parameter key \"%s\" has invalid value %d",
1405 AudioParameter::keyScreenRotation, rotationDegrees);
1406 return BAD_VALUE;
1407 }
1408 return statusTFromBinderStatus(mModule->updateScreenRotation(rotation));
1409 }));
1410 return OK;
1411}
1412
Mikhail Naganovb9a81312023-07-18 13:55:34 -07001413status_t DeviceHalAidl::filterAndUpdateTelephonyParameters(AudioParameter &parameters) {
1414 TIME_CHECK();
1415 using TtyMode = ITelephony::TelecomConfig::TtyMode;
1416 ITelephony::TelecomConfig telConfig;
1417 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1418 parameters, String8(AudioParameter::keyTtyMode),
1419 [&telConfig](const String8& mode) {
1420 if (mode == AudioParameter::valueTtyModeOff) {
1421 telConfig.ttyMode = TtyMode::OFF;
1422 return OK;
1423 } else if (mode == AudioParameter::valueTtyModeFull) {
1424 telConfig.ttyMode = TtyMode::FULL;
1425 return OK;
1426 } else if (mode == AudioParameter::valueTtyModeHco) {
1427 telConfig.ttyMode = TtyMode::HCO;
1428 return OK;
1429 } else if (mode == AudioParameter::valueTtyModeVco) {
1430 telConfig.ttyMode = TtyMode::VCO;
1431 return OK;
1432 }
1433 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1434 AudioParameter::keyTtyMode, mode.c_str());
1435 return BAD_VALUE;
1436 }));
1437 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1438 parameters, String8(AudioParameter::keyHacSetting),
1439 [&telConfig](const String8& onOrOff) {
1440 if (onOrOff == AudioParameter::valueHacOn) {
1441 telConfig.isHacEnabled = Boolean{ .value = true };
1442 return OK;
1443 } else if (onOrOff == AudioParameter::valueHacOff) {
1444 telConfig.isHacEnabled = Boolean{ .value = false };
1445 return OK;
1446 }
1447 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1448 AudioParameter::keyHacSetting, onOrOff.c_str());
1449 return BAD_VALUE;
1450 }));
1451 if (mTelephony != nullptr && telConfig != ITelephony::TelecomConfig{}) {
1452 ITelephony::TelecomConfig newTelConfig;
1453 return statusTFromBinderStatus(
1454 mTelephony->setTelecomConfig(telConfig, &newTelConfig));
1455 }
1456 return OK;
1457}
1458
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001459status_t DeviceHalAidl::findOrCreatePatch(
1460 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
1461 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
1462 requestedPatch.sourcePortConfigIds.end());
1463 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
1464 requestedPatch.sinkPortConfigIds.end());
1465 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
1466}
1467
1468status_t DeviceHalAidl::findOrCreatePatch(
1469 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
1470 AudioPatch* patch, bool* created) {
1471 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
1472 if (patchIt == mPatches.end()) {
1473 TIME_CHECK();
1474 AudioPatch requestedPatch, appliedPatch;
1475 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
1476 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
1477 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
1478 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
1479 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
1480 requestedPatch, &appliedPatch)));
1481 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
1482 *created = true;
1483 } else {
1484 *created = false;
1485 }
1486 *patch = patchIt->second;
1487 return OK;
1488}
1489
jiabin2248fa12023-04-27 22:04:16 +00001490status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device, const AudioConfig* config,
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001491 AudioPortConfig* portConfig, bool* created) {
1492 auto portConfigIt = findPortConfig(device);
1493 if (portConfigIt == mPortConfigs.end()) {
1494 auto portsIt = findPort(device);
1495 if (portsIt == mPorts.end()) {
1496 ALOGE("%s: device port for device %s is not found in the module %s",
1497 __func__, device.toString().c_str(), mInstance.c_str());
1498 return BAD_VALUE;
1499 }
1500 AudioPortConfig requestedPortConfig;
1501 requestedPortConfig.portId = portsIt->first;
jiabin2248fa12023-04-27 22:04:16 +00001502 if (config != nullptr) {
1503 setPortConfigFromConfig(&requestedPortConfig, *config);
1504 }
David Lia8f1e582023-03-30 21:08:06 +08001505 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1506 created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001507 } else {
1508 *created = false;
1509 }
1510 *portConfig = portConfigIt->second;
1511 return OK;
1512}
1513
1514status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001515 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001516 AudioSource source, const std::set<int32_t>& destinationPortIds,
1517 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001518 // These flags get removed one by one in this order when retrying port finding.
1519 static const std::vector<AudioInputFlags> kOptionalInputFlags{
1520 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001521 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001522 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001523 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
1524 AudioIoFlags matchFlags = flags.value();
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001525 auto portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001526 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
1527 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
1528 if (!isBitPositionFlagSet(
1529 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
1530 ++optionalInputFlagsIt;
1531 continue;
1532 }
1533 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
1534 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001535 portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001536 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
1537 "retried with flags %s", __func__, config.toString().c_str(),
1538 flags.value().toString().c_str(), mInstance.c_str(),
1539 matchFlags.toString().c_str());
1540 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001541 if (portsIt == mPorts.end()) {
1542 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001543 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001544 mInstance.c_str());
1545 return BAD_VALUE;
1546 }
1547 AudioPortConfig requestedPortConfig;
1548 requestedPortConfig.portId = portsIt->first;
1549 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001550 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001551 if (matchFlags.getTag() == AudioIoFlags::Tag::input
1552 && source != AudioSource::SYS_RESERVED_INVALID) {
1553 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
1554 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
1555 }
David Lia8f1e582023-03-30 21:08:06 +08001556 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1557 created));
Mikhail Naganov61ccb482023-09-08 17:10:16 -07001558 } else if (portConfigIt == mPortConfigs.end() && !flags.has_value()) {
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001559 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
1560 "and was not created as flags are not specified",
1561 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
1562 return BAD_VALUE;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001563 } else {
David Lia8f1e582023-03-30 21:08:06 +08001564 AudioPortConfig requestedPortConfig = portConfigIt->second;
1565 if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
1566 AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
1567 if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
1568 source != AudioSource::SYS_RESERVED_INVALID) {
1569 mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
1570 }
1571 }
1572
1573 if (requestedPortConfig != portConfigIt->second) {
1574 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1575 created));
1576 } else {
1577 *created = false;
1578 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001579 }
1580 *portConfig = portConfigIt->second;
1581 return OK;
1582}
1583
1584status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001585 const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
1586 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001587 using Tag = AudioPortExt::Tag;
1588 if (requestedPortConfig.ext.getTag() == Tag::mix) {
1589 if (const auto& p = requestedPortConfig;
1590 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001591 !p.format.has_value()) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001592 ALOGW("%s: provided mix port config is not fully specified: %s",
1593 __func__, p.toString().c_str());
1594 return BAD_VALUE;
1595 }
1596 AudioConfig config;
1597 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001598 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
1599 AudioPortMixExtUseCase::Tag::source ?
1600 requestedPortConfig.ext.get<Tag::mix>().usecase.
1601 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001602 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001603 requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
1604 portConfig, created);
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001605 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
1606 return findOrCreatePortConfig(
jiabin2248fa12023-04-27 22:04:16 +00001607 requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
1608 portConfig, created);
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001609 }
1610 ALOGW("%s: unsupported audio port config: %s",
1611 __func__, requestedPortConfig.toString().c_str());
1612 return BAD_VALUE;
1613}
1614
1615DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
1616 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
1617 return std::find_if(mPatches.begin(), mPatches.end(),
1618 [&](const auto& pair) {
1619 const auto& p = pair.second;
1620 std::set<int32_t> patchSrcs(
1621 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
1622 std::set<int32_t> patchSinks(
1623 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
1624 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
1625}
1626
1627DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001628 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1629 return mPorts.find(mDefaultInputPortId);
1630 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1631 return mPorts.find(mDefaultOutputPortId);
1632 }
Mikhail Naganov892f7612023-09-15 18:55:39 -07001633 if (device.address.getTag() != AudioDeviceAddress::id ||
1634 !device.address.get<AudioDeviceAddress::id>().empty()) {
1635 return std::find_if(mPorts.begin(), mPorts.end(),
1636 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
1637 }
1638 // For connection w/o an address, two ports can be found: the template port,
1639 // and a connected port (if exists). Make sure we return the connected port.
1640 DeviceHalAidl::Ports::iterator portIt = mPorts.end();
1641 for (auto it = mPorts.begin(); it != mPorts.end(); ++it) {
1642 if (audioDeviceMatches(device, it->second)) {
1643 if (mConnectedPorts.find(it->first) != mConnectedPorts.end()) {
1644 return it;
1645 } else {
1646 // Will return 'it' if there is no connected port.
1647 portIt = it;
1648 }
1649 }
1650 }
1651 return portIt;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001652}
1653
1654DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001655 const AudioConfig& config, const AudioIoFlags& flags,
1656 const std::set<int32_t>& destinationPortIds) {
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001657 auto belongsToProfile = [&config](const AudioProfile& prof) {
1658 return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
1659 (config.base.channelMask.getTag() == AudioChannelLayout::none ||
1660 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
1661 config.base.channelMask) != prof.channelMasks.end()) &&
1662 (config.base.sampleRate == 0 ||
1663 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
1664 config.base.sampleRate) != prof.sampleRates.end());
1665 };
jiabin2248fa12023-04-27 22:04:16 +00001666 static const std::vector<AudioOutputFlags> kOptionalOutputFlags{AudioOutputFlags::BIT_PERFECT};
1667 int optionalFlags = 0;
1668 auto flagMatches = [&flags, &optionalFlags](const AudioIoFlags& portFlags) {
1669 // Ports should be able to match if the optional flags are not requested.
1670 return portFlags == flags ||
1671 (portFlags.getTag() == AudioIoFlags::Tag::output &&
1672 AudioIoFlags::make<AudioIoFlags::Tag::output>(
1673 portFlags.get<AudioIoFlags::Tag::output>() &
1674 ~optionalFlags) == flags);
1675 };
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001676 auto matcher = [&](const auto& pair) {
1677 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001678 return p.ext.getTag() == AudioPortExt::Tag::mix &&
jiabin2248fa12023-04-27 22:04:16 +00001679 flagMatches(p.flags) &&
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001680 (destinationPortIds.empty() ||
1681 std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
1682 [&](const int32_t destId) { return mRoutingMatrix.count(
1683 std::make_pair(p.id, destId)) != 0; })) &&
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001684 (p.profiles.empty() ||
1685 std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
1686 p.profiles.end()); };
jiabin2248fa12023-04-27 22:04:16 +00001687 auto result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1688 if (result == mPorts.end() && flags.getTag() == AudioIoFlags::Tag::output) {
1689 auto optionalOutputFlagsIt = kOptionalOutputFlags.begin();
1690 while (result == mPorts.end() && optionalOutputFlagsIt != kOptionalOutputFlags.end()) {
1691 if (isBitPositionFlagSet(
1692 flags.get<AudioIoFlags::Tag::output>(), *optionalOutputFlagsIt)) {
1693 // If the flag is set by the request, it must be matched.
1694 ++optionalOutputFlagsIt;
1695 continue;
1696 }
1697 optionalFlags |= makeBitPositionFlagMask(*optionalOutputFlagsIt++);
1698 result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1699 ALOGI("%s: port for config %s, flags %s was not found in the module %s, "
1700 "retried with excluding optional flags %#x", __func__, config.toString().c_str(),
1701 flags.toString().c_str(), mInstance.c_str(), optionalFlags);
1702 }
1703 }
1704 return result;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001705}
1706
1707DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001708 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001709 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001710}
1711
1712DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001713 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001714 using Tag = AudioPortExt::Tag;
1715 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
1716 [&](const auto& pair) {
1717 const auto& p = pair.second;
1718 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
Mikhail Naganove592f1c2023-10-05 17:47:01 -07001719 (!p.sampleRate.has_value() || !p.channelMask.has_value() ||
1720 !p.format.has_value() || !p.flags.has_value()),
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001721 "%s: stored mix port config is not fully specified: %s",
1722 __func__, p.toString().c_str());
1723 return p.ext.getTag() == Tag::mix &&
1724 isConfigEqualToPortConfig(config, p) &&
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001725 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001726 p.ext.template get<Tag::mix>().handle == ioHandle; });
1727}
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001728
Mikhail Naganov66907492023-09-11 17:22:03 -07001729bool DeviceHalAidl::isPortHeldByAStream(int32_t portId) {
1730 // It is assumed that mStreams has already been cleaned up.
1731 for (const auto& streamPair : mStreams) {
1732 int32_t patchId = streamPair.second;
1733 auto patchIt = mPatches.find(patchId);
1734 if (patchIt == mPatches.end()) continue;
1735 for (int32_t id : patchIt->second.sourcePortConfigIds) {
1736 auto portConfigIt = mPortConfigs.find(id);
1737 if (portConfigIt != mPortConfigs.end() && portConfigIt->second.portId == portId) {
1738 return true;
1739 }
1740 }
1741 for (int32_t id : patchIt->second.sinkPortConfigIds) {
1742 auto portConfigIt = mPortConfigs.find(id);
1743 if (portConfigIt != mPortConfigs.end() && portConfigIt->second.portId == portId) {
1744 return true;
1745 }
1746 }
1747 }
1748 return false;
1749}
1750
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001751void DeviceHalAidl::resetPatch(int32_t patchId) {
1752 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1753 mPatches.erase(it);
1754 TIME_CHECK();
1755 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1756 ALOGE("%s: error while resetting patch %d: %s",
1757 __func__, patchId, status.getDescription().c_str());
1758 }
1759 return;
1760 }
1761 ALOGE("%s: patch id %d not found", __func__, patchId);
1762}
1763
1764void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1765 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1766 mPortConfigs.erase(it);
1767 TIME_CHECK();
1768 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1769 !status.isOk()) {
1770 ALOGE("%s: error while resetting port config %d: %s",
1771 __func__, portConfigId, status.getDescription().c_str());
1772 }
1773 return;
1774 }
1775 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1776}
1777
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001778void DeviceHalAidl::resetUnusedPatches() {
1779 // Since patches can be created independently of streams via 'createAudioPatch',
1780 // here we only clean up patches for released streams.
1781 for (auto it = mStreams.begin(); it != mStreams.end(); ) {
1782 if (auto streamSp = it->first.promote(); streamSp) {
1783 ++it;
1784 } else {
1785 resetPatch(it->second);
1786 it = mStreams.erase(it);
1787 }
1788 }
1789}
1790
1791void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
1792 resetUnusedPatches();
1793 resetUnusedPortConfigs();
1794}
1795
1796void DeviceHalAidl::resetUnusedPortConfigs() {
1797 // The assumption is that port configs are used to create patches
1798 // (or to open streams, but that involves creation of patches, too). Thus,
1799 // orphaned port configs can and should be reset.
Mikhail Naganov66907492023-09-11 17:22:03 -07001800 std::map<int32_t, int32_t /*portID*/> portConfigIds;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001801 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
1802 std::inserter(portConfigIds, portConfigIds.end()),
Mikhail Naganov66907492023-09-11 17:22:03 -07001803 [](const auto& pcPair) { return std::make_pair(pcPair.first, pcPair.second.portId); });
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001804 for (const auto& p : mPatches) {
1805 for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
1806 for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
1807 }
jiabin2248fa12023-04-27 22:04:16 +00001808 for (int32_t id : mInitialPortConfigIds) {
1809 portConfigIds.erase(id);
1810 }
Mikhail Naganov66907492023-09-11 17:22:03 -07001811 std::set<int32_t> retryDeviceDisconnection;
1812 for (const auto& portConfigAndIdPair : portConfigIds) {
1813 resetPortConfig(portConfigAndIdPair.first);
Mikhail Naganov892f7612023-09-15 18:55:39 -07001814 if (const auto it = mConnectedPorts.find(portConfigAndIdPair.second);
1815 it != mConnectedPorts.end() && it->second) {
Mikhail Naganov66907492023-09-11 17:22:03 -07001816 retryDeviceDisconnection.insert(portConfigAndIdPair.second);
1817 }
1818 }
1819 for (int32_t portId : retryDeviceDisconnection) {
1820 if (!isPortHeldByAStream(portId)) {
1821 TIME_CHECK();
1822 if (auto status = mModule->disconnectExternalDevice(portId); status.isOk()) {
1823 mPorts.erase(portId);
Mikhail Naganov892f7612023-09-15 18:55:39 -07001824 mConnectedPorts.erase(portId);
Mikhail Naganov66907492023-09-11 17:22:03 -07001825 ALOGD("%s: executed postponed external device disconnection for port ID %d",
1826 __func__, portId);
1827 }
1828 }
1829 }
1830 if (!retryDeviceDisconnection.empty()) {
1831 updateRoutes();
1832 }
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001833}
1834
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001835status_t DeviceHalAidl::updateRoutes() {
1836 TIME_CHECK();
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001837 RETURN_STATUS_IF_ERROR(
Mikhail Naganov2d814892023-04-24 13:06:04 -07001838 statusTFromBinderStatus(mModule->getAudioRoutes(&mRoutes)));
1839 ALOGW_IF(mRoutes.empty(), "%s: module %s returned an empty list of audio routes",
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001840 __func__, mInstance.c_str());
1841 mRoutingMatrix.clear();
Mikhail Naganov2d814892023-04-24 13:06:04 -07001842 for (const auto& r : mRoutes) {
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001843 for (auto portId : r.sourcePortIds) {
1844 mRoutingMatrix.emplace(r.sinkPortId, portId);
1845 mRoutingMatrix.emplace(portId, r.sinkPortId);
1846 }
1847 }
1848 return OK;
1849}
1850
Mikhail Naganovb0c55252023-02-08 16:59:41 -08001851void DeviceHalAidl::clearCallbacks(void* cookie) {
1852 std::lock_guard l(mLock);
1853 mCallbacks.erase(cookie);
1854}
1855
1856sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1857 return getCallbackImpl(cookie, &Callbacks::out);
1858}
1859
1860void DeviceHalAidl::setStreamOutCallback(
1861 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1862 setCallbackImpl(cookie, &Callbacks::out, cb);
1863}
1864
1865sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1866 void* cookie) {
1867 return getCallbackImpl(cookie, &Callbacks::event);
1868}
1869
1870void DeviceHalAidl::setStreamOutEventCallback(
1871 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1872 setCallbackImpl(cookie, &Callbacks::event, cb);
1873}
1874
1875sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1876 void* cookie) {
1877 return getCallbackImpl(cookie, &Callbacks::latency);
1878}
1879
1880void DeviceHalAidl::setStreamOutLatencyModeCallback(
1881 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1882 setCallbackImpl(cookie, &Callbacks::latency, cb);
1883}
1884
1885template<class C>
1886sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1887 std::lock_guard l(mLock);
1888 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1889 return ((it->second).*field).promote();
1890 }
1891 return nullptr;
1892}
1893template<class C>
1894void DeviceHalAidl::setCallbackImpl(
1895 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1896 std::lock_guard l(mLock);
1897 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1898 (it->second).*field = cb;
1899 }
1900}
1901
Mikhail Naganov31d46652023-01-10 18:29:25 +00001902} // namespace android