blob: c6552ef1116840b498889f878ec19cbb3739e046 [file] [log] [blame]
Shunkai Yao51202502022-12-12 06:11:46 +00001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "DeviceHalAidl"
Mikhail Naganov89a9f742023-01-30 12:33:18 -080018// #define LOG_NDEBUG 0
Shunkai Yao51202502022-12-12 06:11:46 +000019
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080020#include <algorithm>
21#include <forward_list>
22
Mikhail Naganovdfd594e2023-02-08 16:59:41 -080023#include <aidl/android/hardware/audio/core/BnStreamCallback.h>
24#include <aidl/android/hardware/audio/core/BnStreamOutEventCallback.h>
Mikhail Naganovfab697c2023-01-11 19:33:13 +000025#include <aidl/android/hardware/audio/core/StreamDescriptor.h>
26#include <error/expected_utils.h>
27#include <media/AidlConversionCppNdk.h>
Mikhail Naganov25bc9a22023-04-21 18:48:16 -070028#include <media/AidlConversionNdkCpp.h>
Mikhail Naganovfab697c2023-01-11 19:33:13 +000029#include <media/AidlConversionUtil.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000030#include <mediautils/TimeCheck.h>
Mikhail Naganov89a9f742023-01-30 12:33:18 -080031#include <Utils.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000032#include <utils/Log.h>
Shunkai Yao51202502022-12-12 06:11:46 +000033
Mikhail Naganov31d46652023-01-10 18:29:25 +000034#include "DeviceHalAidl.h"
Mikhail Naganova82a69d2023-06-14 16:31:32 -070035#include "EffectHalAidl.h"
Mikhail Naganov31d46652023-01-10 18:29:25 +000036#include "StreamHalAidl.h"
37
Mikhail Naganovfab697c2023-01-11 19:33:13 +000038using aidl::android::aidl_utils::statusTFromBinderStatus;
Mikhail Naganovccc82112023-04-27 18:14:15 -070039using aidl::android::media::audio::common::Boolean;
Mikhail Naganove93a0862023-03-15 17:06:59 -070040using aidl::android::media::audio::common::AudioChannelLayout;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080041using aidl::android::media::audio::common::AudioConfig;
42using aidl::android::media::audio::common::AudioDevice;
David Li9cf5e622023-03-21 00:51:10 +080043using aidl::android::media::audio::common::AudioDeviceAddress;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080044using aidl::android::media::audio::common::AudioDeviceType;
Mikhail Naganov69557132023-09-07 15:29:01 -070045using aidl::android::media::audio::common::AudioFormatDescription;
Mikhail Naganove93a0862023-03-15 17:06:59 -070046using aidl::android::media::audio::common::AudioFormatType;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080047using aidl::android::media::audio::common::AudioInputFlags;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080048using aidl::android::media::audio::common::AudioIoFlags;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -080049using aidl::android::media::audio::common::AudioLatencyMode;
David Li9cf5e622023-03-21 00:51:10 +080050using aidl::android::media::audio::common::AudioMMapPolicy;
51using aidl::android::media::audio::common::AudioMMapPolicyInfo;
52using aidl::android::media::audio::common::AudioMMapPolicyType;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000053using aidl::android::media::audio::common::AudioMode;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080054using aidl::android::media::audio::common::AudioOutputFlags;
55using aidl::android::media::audio::common::AudioPort;
56using aidl::android::media::audio::common::AudioPortConfig;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080057using aidl::android::media::audio::common::AudioPortDeviceExt;
David Li9cf5e622023-03-21 00:51:10 +080058using aidl::android::media::audio::common::AudioPortExt;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -080059using aidl::android::media::audio::common::AudioPortMixExt;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -080060using aidl::android::media::audio::common::AudioPortMixExtUseCase;
Mikhail Naganove93a0862023-03-15 17:06:59 -070061using aidl::android::media::audio::common::AudioProfile;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080062using aidl::android::media::audio::common::AudioSource;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000063using aidl::android::media::audio::common::Float;
David Li9cf5e622023-03-21 00:51:10 +080064using aidl::android::media::audio::common::Int;
65using aidl::android::media::audio::common::MicrophoneDynamicInfo;
66using aidl::android::media::audio::common::MicrophoneInfo;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -070067using aidl::android::media::audio::IHalAdapterVendorExtension;
Mikhail Naganov6352e822023-03-09 18:22:36 -080068using aidl::android::hardware::audio::common::getFrameSizeInBytes;
69using aidl::android::hardware::audio::common::isBitPositionFlagSet;
Mikhail Naganove93a0862023-03-15 17:06:59 -070070using aidl::android::hardware::audio::common::isDefaultAudioFormat;
Mikhail Naganov6352e822023-03-09 18:22:36 -080071using aidl::android::hardware::audio::common::makeBitPositionFlagMask;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080072using aidl::android::hardware::audio::common::RecordTrackMetadata;
73using aidl::android::hardware::audio::core::AudioPatch;
Mikhail Naganov289468a2023-03-29 10:06:15 -070074using aidl::android::hardware::audio::core::AudioRoute;
Mikhail Naganovccc82112023-04-27 18:14:15 -070075using aidl::android::hardware::audio::core::IBluetooth;
76using aidl::android::hardware::audio::core::IBluetoothA2dp;
77using aidl::android::hardware::audio::core::IBluetoothLe;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000078using aidl::android::hardware::audio::core::IModule;
79using aidl::android::hardware::audio::core::ITelephony;
Mikhail Naganove93a0862023-03-15 17:06:59 -070080using aidl::android::hardware::audio::core::ModuleDebug;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000081using aidl::android::hardware::audio::core::StreamDescriptor;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -070082using aidl::android::hardware::audio::core::VendorParameter;
Mikhail Naganov31d46652023-01-10 18:29:25 +000083
84namespace android {
85
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080086namespace {
87
88bool isConfigEqualToPortConfig(const AudioConfig& config, const AudioPortConfig& portConfig) {
89 return portConfig.sampleRate.value().value == config.base.sampleRate &&
90 portConfig.channelMask.value() == config.base.channelMask &&
91 portConfig.format.value() == config.base.format;
92}
93
94void setConfigFromPortConfig(AudioConfig* config, const AudioPortConfig& portConfig) {
95 config->base.sampleRate = portConfig.sampleRate.value().value;
96 config->base.channelMask = portConfig.channelMask.value();
97 config->base.format = portConfig.format.value();
98}
99
100void setPortConfigFromConfig(AudioPortConfig* portConfig, const AudioConfig& config) {
Mikhail Naganov69557132023-09-07 15:29:01 -0700101 if (config.base.sampleRate != 0) {
102 portConfig->sampleRate = Int{ .value = config.base.sampleRate };
103 }
104 if (config.base.channelMask != AudioChannelLayout{}) {
105 portConfig->channelMask = config.base.channelMask;
106 }
107 if (config.base.format != AudioFormatDescription{}) {
108 portConfig->format = config.base.format;
109 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800110}
111
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700112// Note: these converters are for types defined in different AIDL files. Although these
113// AIDL files are copies of each other, however formally these are different types
114// thus we don't use a conversion via a parcelable.
115ConversionResult<media::AudioRoute> ndk2cpp_AudioRoute(const AudioRoute& ndk) {
116 media::AudioRoute cpp;
117 cpp.sourcePortIds.insert(
118 cpp.sourcePortIds.end(), ndk.sourcePortIds.begin(), ndk.sourcePortIds.end());
119 cpp.sinkPortId = ndk.sinkPortId;
120 cpp.isExclusive = ndk.isExclusive;
David Li9cf5e622023-03-21 00:51:10 +0800121 return cpp;
122}
123
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700124template<typename T>
125std::shared_ptr<T> retrieveSubInterface(const std::shared_ptr<IModule>& module,
126 ::ndk::ScopedAStatus (IModule::*getT)(std::shared_ptr<T>*)) {
127 if (module != nullptr) {
128 std::shared_ptr<T> instance;
129 if (auto status = (module.get()->*getT)(&instance); status.isOk()) {
130 return instance;
131 }
132 }
133 return nullptr;
134}
135
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800136} // namespace
137
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700138DeviceHalAidl::DeviceHalAidl(const std::string& instance, const std::shared_ptr<IModule>& module,
139 const std::shared_ptr<IHalAdapterVendorExtension>& vext)
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700140 : ConversionHelperAidl("DeviceHalAidl"),
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700141 mInstance(instance), mModule(module), mVendorExt(vext),
Mikhail Naganovccc82112023-04-27 18:14:15 -0700142 mTelephony(retrieveSubInterface<ITelephony>(module, &IModule::getTelephony)),
143 mBluetooth(retrieveSubInterface<IBluetooth>(module, &IModule::getBluetooth)),
144 mBluetoothA2dp(retrieveSubInterface<IBluetoothA2dp>(module, &IModule::getBluetoothA2dp)),
145 mBluetoothLe(retrieveSubInterface<IBluetoothLe>(module, &IModule::getBluetoothLe)) {
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700146}
147
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700148status_t DeviceHalAidl::getAudioPorts(std::vector<media::audio::common::AudioPort> *ports) {
Mikhail Naganov9e459d72023-05-05 17:36:39 -0700149 return ::aidl::android::convertContainer(mPorts, ports,
150 [](const Ports::value_type& pair) { return ndk2cpp_AudioPort(pair.second); });
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700151}
152
153status_t DeviceHalAidl::getAudioRoutes(std::vector<media::AudioRoute> *routes) {
154 *routes = VALUE_OR_RETURN_STATUS(
155 ::aidl::android::convertContainer<std::vector<media::AudioRoute>>(
156 mRoutes, ndk2cpp_AudioRoute));
157 return OK;
158}
159
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700160status_t DeviceHalAidl::getSupportedModes(std::vector<media::audio::common::AudioMode> *modes) {
161 TIME_CHECK();
162 if (modes == nullptr) {
163 return BAD_VALUE;
164 }
165 if (mModule == nullptr) return NO_INIT;
166 if (mTelephony == nullptr) return INVALID_OPERATION;
167 std::vector<AudioMode> aidlModes;
168 RETURN_STATUS_IF_ERROR(
169 statusTFromBinderStatus(mTelephony->getSupportedAudioModes(&aidlModes)));
170 *modes = VALUE_OR_RETURN_STATUS(
171 ::aidl::android::convertContainer<std::vector<media::audio::common::AudioMode>>(
172 aidlModes, ndk2cpp_AudioMode));
173 return OK;
174}
175
Mikhail Naganov31d46652023-01-10 18:29:25 +0000176status_t DeviceHalAidl::getSupportedDevices(uint32_t*) {
177 // Obsolete.
178 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +0000179}
180
181status_t DeviceHalAidl::initCheck() {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800182 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000183 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800184 std::vector<AudioPort> ports;
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700185 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800186 ALOGW_IF(ports.empty(), "%s: module %s returned an empty list of audio ports",
187 __func__, mInstance.c_str());
188 std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()),
189 [](const auto& p) { return std::make_pair(p.id, p); });
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800190 mDefaultInputPortId = mDefaultOutputPortId = -1;
191 const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
192 for (const auto& pair : mPorts) {
193 const auto& p = pair.second;
194 if (p.ext.getTag() == AudioPortExt::Tag::device &&
195 (p.ext.get<AudioPortExt::Tag::device>().flags & defaultDeviceFlag) != 0) {
196 if (p.flags.getTag() == AudioIoFlags::Tag::input) {
197 mDefaultInputPortId = p.id;
198 } else if (p.flags.getTag() == AudioIoFlags::Tag::output) {
199 mDefaultOutputPortId = p.id;
200 }
201 }
202 }
203 ALOGI("%s: module %s default port ids: input %d, output %d",
204 __func__, mInstance.c_str(), mDefaultInputPortId, mDefaultOutputPortId);
Mikhail Naganov289468a2023-03-29 10:06:15 -0700205 RETURN_STATUS_IF_ERROR(updateRoutes());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800206 std::vector<AudioPortConfig> portConfigs;
207 RETURN_STATUS_IF_ERROR(
208 statusTFromBinderStatus(mModule->getAudioPortConfigs(&portConfigs))); // OK if empty
209 std::transform(portConfigs.begin(), portConfigs.end(),
210 std::inserter(mPortConfigs, mPortConfigs.end()),
211 [](const auto& p) { return std::make_pair(p.id, p); });
jiabin9c07faf2023-04-26 22:00:44 +0000212 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
213 std::inserter(mInitialPortConfigIds, mInitialPortConfigIds.end()),
214 [](const auto& pcPair) { return pcPair.first; });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800215 std::vector<AudioPatch> patches;
216 RETURN_STATUS_IF_ERROR(
217 statusTFromBinderStatus(mModule->getAudioPatches(&patches))); // OK if empty
218 std::transform(patches.begin(), patches.end(),
219 std::inserter(mPatches, mPatches.end()),
220 [](const auto& p) { return std::make_pair(p.id, p); });
Shunkai Yao51202502022-12-12 06:11:46 +0000221 return OK;
222}
223
224status_t DeviceHalAidl::setVoiceVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000225 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000226 if (!mModule) return NO_INIT;
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700227 if (mTelephony == nullptr) return INVALID_OPERATION;
228 ITelephony::TelecomConfig inConfig{ .voiceVolume = Float{volume} }, outConfig;
229 RETURN_STATUS_IF_ERROR(
230 statusTFromBinderStatus(mTelephony->setTelecomConfig(inConfig, &outConfig)));
231 ALOGW_IF(outConfig.voiceVolume.has_value() && volume != outConfig.voiceVolume.value().value,
232 "%s: the resulting voice volume %f is not the same as requested %f",
233 __func__, outConfig.voiceVolume.value().value, volume);
234 return OK;
Shunkai Yao51202502022-12-12 06:11:46 +0000235}
236
237status_t DeviceHalAidl::setMasterVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000238 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000239 if (!mModule) return NO_INIT;
240 return statusTFromBinderStatus(mModule->setMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000241}
242
243status_t DeviceHalAidl::getMasterVolume(float *volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000244 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000245 if (!mModule) return NO_INIT;
246 return statusTFromBinderStatus(mModule->getMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000247}
248
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000249status_t DeviceHalAidl::setMode(audio_mode_t mode) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000250 TIME_CHECK();
251 if (!mModule) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000252 AudioMode audioMode = VALUE_OR_FATAL(::aidl::android::legacy2aidl_audio_mode_t_AudioMode(mode));
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700253 if (mTelephony != nullptr) {
254 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mTelephony->switchAudioMode(audioMode)));
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000255 }
256 return statusTFromBinderStatus(mModule->updateAudioMode(audioMode));
Shunkai Yao51202502022-12-12 06:11:46 +0000257}
258
259status_t DeviceHalAidl::setMicMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000260 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000261 if (!mModule) return NO_INIT;
262 return statusTFromBinderStatus(mModule->setMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000263}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000264
Shunkai Yao51202502022-12-12 06:11:46 +0000265status_t DeviceHalAidl::getMicMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000266 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000267 if (!mModule) return NO_INIT;
268 return statusTFromBinderStatus(mModule->getMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000269}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000270
Shunkai Yao51202502022-12-12 06:11:46 +0000271status_t DeviceHalAidl::setMasterMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000272 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000273 if (!mModule) return NO_INIT;
274 return statusTFromBinderStatus(mModule->setMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000275}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000276
Shunkai Yao51202502022-12-12 06:11:46 +0000277status_t DeviceHalAidl::getMasterMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000278 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000279 if (!mModule) return NO_INIT;
280 return statusTFromBinderStatus(mModule->getMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000281}
282
Mikhail Naganovccc82112023-04-27 18:14:15 -0700283status_t DeviceHalAidl::setParameters(const String8& kvPairs) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000284 if (!mModule) return NO_INIT;
Mikhail Naganovccc82112023-04-27 18:14:15 -0700285 AudioParameter parameters(kvPairs);
286 ALOGD("%s: parameters: \"%s\"", __func__, parameters.toString().c_str());
287
288 if (status_t status = filterAndUpdateBtA2dpParameters(parameters); status != OK) {
289 ALOGW("%s: filtering or updating BT A2DP parameters failed: %d", __func__, status);
290 }
291 if (status_t status = filterAndUpdateBtHfpParameters(parameters); status != OK) {
292 ALOGW("%s: filtering or updating BT HFP parameters failed: %d", __func__, status);
293 }
294 if (status_t status = filterAndUpdateBtLeParameters(parameters); status != OK) {
295 ALOGW("%s: filtering or updating BT LE parameters failed: %d", __func__, status);
296 }
297 if (status_t status = filterAndUpdateBtScoParameters(parameters); status != OK) {
298 ALOGW("%s: filtering or updating BT SCO parameters failed: %d", __func__, status);
299 }
Mikhail Naganove92c34b2023-05-31 14:24:48 -0700300 if (status_t status = filterAndUpdateScreenParameters(parameters); status != OK) {
301 ALOGW("%s: filtering or updating screen parameters failed: %d", __func__, status);
302 }
Mikhail Naganovb9a81312023-07-18 13:55:34 -0700303 if (status_t status = filterAndUpdateTelephonyParameters(parameters); status != OK) {
304 ALOGW("%s: filtering or updating telephony parameters failed: %d", __func__, status);
305 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700306 return parseAndSetVendorParameters(mVendorExt, mModule, parameters);
Shunkai Yao51202502022-12-12 06:11:46 +0000307}
308
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700309status_t DeviceHalAidl::getParameters(const String8& keys, String8 *values) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000310 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000311 if (!mModule) return NO_INIT;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700312 if (values == nullptr) {
313 return BAD_VALUE;
314 }
315 AudioParameter parameterKeys(keys), result;
316 if (status_t status = filterAndRetrieveBtA2dpParameters(parameterKeys, &result); status != OK) {
317 ALOGW("%s: filtering or retrieving BT A2DP parameters failed: %d", __func__, status);
318 }
319 *values = result.toString();
320 return parseAndGetVendorParameters(mVendorExt, mModule, parameterKeys, values);
Shunkai Yao51202502022-12-12 06:11:46 +0000321}
322
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800323namespace {
324
325class Cleanup {
326 public:
327 typedef void (DeviceHalAidl::*Cleaner)(int32_t);
328
329 Cleanup(DeviceHalAidl* device, Cleaner cleaner, int32_t id) :
330 mDevice(device), mCleaner(cleaner), mId(id) {}
331 ~Cleanup() { clean(); }
332 void clean() {
333 if (mDevice != nullptr) (mDevice->*mCleaner)(mId);
334 disarm();
335 }
336 void disarm() { mDevice = nullptr; }
337
338 private:
339 DeviceHalAidl* mDevice;
340 const Cleaner mCleaner;
341 const int32_t mId;
342};
343
344} // namespace
345
346// Since the order of container elements destruction is unspecified,
347// ensure that cleanups are performed from the most recent one and upwards.
348// This is the same as if there were individual Cleanup instances on the stack,
349// however the bonus is that we can disarm all of them with just one statement.
350class DeviceHalAidl::Cleanups : public std::forward_list<Cleanup> {
351 public:
352 ~Cleanups() { for (auto& c : *this) c.clean(); }
353 void disarmAll() { for (auto& c : *this) c.disarm(); }
354};
355
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800356status_t DeviceHalAidl::getInputBufferSize(const struct audio_config* config, size_t* size) {
357 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
358 if (size == nullptr) return BAD_VALUE;
359 TIME_CHECK();
360 if (!mModule) return NO_INIT;
361 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
362 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
363 AudioDevice aidlDevice;
364 aidlDevice.type.type = AudioDeviceType::IN_DEFAULT;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800365 AudioSource aidlSource = AudioSource::DEFAULT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800366 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
367 AudioPortConfig mixPortConfig;
368 Cleanups cleanups;
369 audio_config writableConfig = *config;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700370 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800371 RETURN_STATUS_IF_ERROR(prepareToOpenStream(0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700372 &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800373 *size = aidlConfig.frameCount *
374 getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
375 // Do not disarm cleanups to release temporary port configs.
376 return OK;
377}
378
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800379status_t DeviceHalAidl::prepareToOpenStream(
380 int32_t aidlHandle, const AudioDevice& aidlDevice, const AudioIoFlags& aidlFlags,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800381 AudioSource aidlSource, struct audio_config* config,
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800382 Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700383 AudioPatch* aidlPatch) {
384 ALOGD("%p %s::%s: handle %d, device %s, flags %s, source %s, config %s, mix port config %s",
385 this, getClassName().c_str(), __func__, aidlHandle, aidlDevice.toString().c_str(),
386 aidlFlags.toString().c_str(), toString(aidlSource).c_str(),
387 aidlConfig->toString().c_str(), mixPortConfig->toString().c_str());
jiabin9c07faf2023-04-26 22:00:44 +0000388 resetUnusedPatchesAndPortConfigs();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800389 const bool isInput = aidlFlags.getTag() == AudioIoFlags::Tag::input;
390 // Find / create AudioPortConfigs for the device port and the mix port,
391 // then find / create a patch between them, and open a stream on the mix port.
392 AudioPortConfig devicePortConfig;
393 bool created = false;
jiabin9c07faf2023-04-26 22:00:44 +0000394 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, aidlConfig,
395 &devicePortConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800396 if (created) {
397 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
398 }
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800399 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*aidlConfig, aidlFlags, aidlHandle, aidlSource,
Mikhail Naganov289468a2023-03-29 10:06:15 -0700400 std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800401 if (created) {
402 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
403 }
404 setConfigFromPortConfig(aidlConfig, *mixPortConfig);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800405 if (isInput) {
406 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700407 {devicePortConfig.id}, {mixPortConfig->id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800408 } else {
409 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700410 {mixPortConfig->id}, {devicePortConfig.id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800411 }
412 if (created) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700413 cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, aidlPatch->id);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800414 }
415 if (aidlConfig->frameCount <= 0) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700416 aidlConfig->frameCount = aidlPatch->minimumStreamBufferSizeFrames;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800417 }
418 *config = VALUE_OR_RETURN_STATUS(
419 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(*aidlConfig, isInput));
420 return OK;
421}
422
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800423namespace {
424
425class StreamCallbackBase {
426 protected:
427 explicit StreamCallbackBase(const sp<CallbackBroker>& broker) : mBroker(broker) {}
428 public:
429 void* getCookie() const { return mCookie; }
430 void setCookie(void* cookie) { mCookie = cookie; }
431 sp<CallbackBroker> getBroker() const {
432 if (void* cookie = mCookie; cookie != nullptr) return mBroker.promote();
433 return nullptr;
434 }
435 private:
436 const wp<CallbackBroker> mBroker;
437 std::atomic<void*> mCookie;
438};
439
440template<class C>
441class StreamCallbackBaseHelper {
442 protected:
443 explicit StreamCallbackBaseHelper(const StreamCallbackBase& base) : mBase(base) {}
444 sp<C> getCb(const sp<CallbackBroker>& broker, void* cookie);
445 using CbRef = const sp<C>&;
446 ndk::ScopedAStatus runCb(const std::function<void(CbRef cb)>& f) {
447 if (auto cb = getCb(mBase.getBroker(), mBase.getCookie()); cb != nullptr) f(cb);
448 return ndk::ScopedAStatus::ok();
449 }
450 private:
451 const StreamCallbackBase& mBase;
452};
453
454template<>
455sp<StreamOutHalInterfaceCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>::getCb(
456 const sp<CallbackBroker>& broker, void* cookie) {
457 if (broker != nullptr) return broker->getStreamOutCallback(cookie);
458 return nullptr;
459}
460
461template<>
462sp<StreamOutHalInterfaceEventCallback>
463StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::getCb(
464 const sp<CallbackBroker>& broker, void* cookie) {
465 if (broker != nullptr) return broker->getStreamOutEventCallback(cookie);
466 return nullptr;
467}
468
469template<>
470sp<StreamOutHalInterfaceLatencyModeCallback>
471StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::getCb(
472 const sp<CallbackBroker>& broker, void* cookie) {
473 if (broker != nullptr) return broker->getStreamOutLatencyModeCallback(cookie);
474 return nullptr;
475}
476
477/*
478Note on the callback ownership.
479
480In the Binder ownership model, the server implementation is kept alive
481as long as there is any client (proxy object) alive. This is done by
482incrementing the refcount of the server-side object by the Binder framework.
483When it detects that the last client is gone, it decrements the refcount back.
484
485Thus, it is not needed to keep any references to StreamCallback on our
486side (after we have sent an instance to the client), because we are
487the server-side. The callback object will be kept alive as long as the HAL server
488holds a strong ref to IStreamCallback proxy.
489*/
490
491class OutputStreamCallbackAidl : public StreamCallbackBase,
492 public StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>,
493 public ::aidl::android::hardware::audio::core::BnStreamCallback {
494 public:
495 explicit OutputStreamCallbackAidl(const sp<CallbackBroker>& broker)
496 : StreamCallbackBase(broker),
497 StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>(
498 *static_cast<StreamCallbackBase*>(this)) {}
499 ndk::ScopedAStatus onTransferReady() override {
500 return runCb([](CbRef cb) { cb->onWriteReady(); });
501 }
502 ndk::ScopedAStatus onError() override {
503 return runCb([](CbRef cb) { cb->onError(); });
504 }
505 ndk::ScopedAStatus onDrainReady() override {
506 return runCb([](CbRef cb) { cb->onDrainReady(); });
507 }
508};
509
510class OutputStreamEventCallbackAidl :
511 public StreamCallbackBase,
512 public StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>,
513 public StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>,
514 public ::aidl::android::hardware::audio::core::BnStreamOutEventCallback {
515 public:
516 explicit OutputStreamEventCallbackAidl(const sp<CallbackBroker>& broker)
517 : StreamCallbackBase(broker),
518 StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>(
519 *static_cast<StreamCallbackBase*>(this)),
520 StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>(
521 *static_cast<StreamCallbackBase*>(this)) {}
522 ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& in_audioMetadata) override {
523 std::basic_string<uint8_t> halMetadata(in_audioMetadata.begin(), in_audioMetadata.end());
524 return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb(
525 [&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); });
526 }
527 ndk::ScopedAStatus onRecommendedLatencyModeChanged(
528 const std::vector<AudioLatencyMode>& in_modes) override {
529 auto halModes = VALUE_OR_FATAL(
530 ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
531 in_modes,
532 ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
533 return StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::runCb(
534 [&halModes](auto cb) { cb->onRecommendedLatencyModeChanged(halModes); });
535 }
536};
537
538} // namespace
539
Mikhail Naganov31d46652023-01-10 18:29:25 +0000540status_t DeviceHalAidl::openOutputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800541 audio_io_handle_t handle, audio_devices_t devices,
542 audio_output_flags_t flags, struct audio_config* config,
543 const char* address,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000544 sp<StreamOutHalInterface>* outStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800545 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000546 if (!outStream || !config) {
547 return BAD_VALUE;
548 }
549 TIME_CHECK();
550 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800551 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
552 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
553 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
554 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, false /*isInput*/));
555 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
556 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
557 int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
558 ::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
559 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
560 AudioPortConfig mixPortConfig;
561 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700562 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800563 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
564 AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700565 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800566 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
567 args.portConfigId = mixPortConfig.id;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800568 const bool isOffload = isBitPositionFlagSet(
569 aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD);
570 std::shared_ptr<OutputStreamCallbackAidl> streamCb;
571 if (isOffload) {
572 streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
573 }
574 auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
575 if (isOffload) {
576 args.offloadInfo = aidlConfig.offloadInfo;
577 args.callback = streamCb;
578 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800579 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800580 args.eventCallback = eventCb;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800581 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
582 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800583 StreamContextAidl context(ret.desc, isOffload);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800584 if (!context.isValid()) {
585 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
586 __func__, ret.desc.toString().c_str());
587 return NO_INIT;
588 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700589 *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700590 std::move(ret.stream), mVendorExt, this /*callbackBroker*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700591 mStreams.insert(std::pair(*outStream, aidlPatch.id));
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800592 void* cbCookie = (*outStream).get();
593 {
594 std::lock_guard l(mLock);
595 mCallbacks.emplace(cbCookie, Callbacks{});
596 }
597 if (streamCb) streamCb->setCookie(cbCookie);
598 eventCb->setCookie(cbCookie);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800599 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000600 return OK;
601}
602
Mikhail Naganov31d46652023-01-10 18:29:25 +0000603status_t DeviceHalAidl::openInputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800604 audio_io_handle_t handle, audio_devices_t devices,
605 struct audio_config* config, audio_input_flags_t flags,
606 const char* address, audio_source_t source,
607 audio_devices_t outputDevice, const char* outputDeviceAddress,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000608 sp<StreamInHalInterface>* inStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800609 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000610 if (!inStream || !config) {
611 return BAD_VALUE;
612 }
613 TIME_CHECK();
614 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800615 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
616 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
617 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
618 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
619 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
620 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
621 int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
622 ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
623 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
624 AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
625 ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
626 AudioPortConfig mixPortConfig;
627 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700628 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800629 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700630 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800631 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
632 args.portConfigId = mixPortConfig.id;
633 RecordTrackMetadata aidlTrackMetadata{
634 .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
635 if (outputDevice != AUDIO_DEVICE_NONE) {
636 aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
637 ::aidl::android::legacy2aidl_audio_device_AudioDevice(
638 outputDevice, outputDeviceAddress));
639 }
640 args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
641 args.bufferSizeFrames = aidlConfig.frameCount;
642 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
643 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800644 StreamContextAidl context(ret.desc, false /*isAsynchronous*/);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800645 if (!context.isValid()) {
646 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
647 __func__, ret.desc.toString().c_str());
648 return NO_INIT;
649 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700650 *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700651 std::move(ret.stream), mVendorExt, this /*micInfoProvider*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700652 mStreams.insert(std::pair(*inStream, aidlPatch.id));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800653 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000654 return OK;
655}
656
657status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
658 *supportsPatches = true;
659 return OK;
660}
661
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800662status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
663 const struct audio_port_config* sources,
664 unsigned int num_sinks,
665 const struct audio_port_config* sinks,
666 audio_patch_handle_t* patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800667 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000668 TIME_CHECK();
669 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800670 if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
671 sources == nullptr || sinks == nullptr || patch == nullptr) {
672 return BAD_VALUE;
673 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800674 // When the patch handle (*patch) is AUDIO_PATCH_HANDLE_NONE, it means
675 // the framework wants to create a new patch. The handle has to be generated
676 // by the HAL. Since handles generated this way can only be unique within
677 // a HAL module, the framework generates a globally unique handle, and maps
678 // it on the <HAL module, patch handle> pair.
679 // When the patch handle is set, it meant the framework intends to update
680 // an existing patch.
681 //
682 // This behavior corresponds to HAL module behavior, with the only difference
683 // that the HAL module uses `int32_t` for patch IDs. The following assert ensures
684 // that both the framework and the HAL use the same value for "no ID":
685 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
686 int32_t halPatchId = static_cast<int32_t>(*patch);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800687
688 // Upon conversion, mix port configs contain audio configuration, while
689 // device port configs contain device address. This data is used to find
690 // or create HAL configs.
691 std::vector<AudioPortConfig> aidlSources, aidlSinks;
692 for (unsigned int i = 0; i < num_sources; ++i) {
693 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
694 sources[i].role, sources[i].type)) ==
695 ::aidl::android::AudioPortDirection::INPUT;
696 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
697 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
698 sources[i], isInput, 0)));
699 }
700 for (unsigned int i = 0; i < num_sinks; ++i) {
701 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
702 sinks[i].role, sinks[i].type)) ==
703 ::aidl::android::AudioPortDirection::INPUT;
704 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
705 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
706 sinks[i], isInput, 0)));
707 }
708 Cleanups cleanups;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800709 auto existingPatchIt = halPatchId != 0 ? mPatches.find(halPatchId): mPatches.end();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800710 AudioPatch aidlPatch;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800711 if (existingPatchIt != mPatches.end()) {
712 aidlPatch = existingPatchIt->second;
713 aidlPatch.sourcePortConfigIds.clear();
714 aidlPatch.sinkPortConfigIds.clear();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800715 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800716 ALOGD("%s: sources: %s, sinks: %s",
717 __func__, ::android::internal::ToString(aidlSources).c_str(),
718 ::android::internal::ToString(aidlSinks).c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800719 auto fillPortConfigs = [&](
Mikhail Naganov289468a2023-03-29 10:06:15 -0700720 const std::vector<AudioPortConfig>& configs,
721 const std::set<int32_t>& destinationPortIds,
722 std::vector<int32_t>* ids, std::set<int32_t>* portIds) -> status_t {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800723 for (const auto& s : configs) {
724 AudioPortConfig portConfig;
725 bool created = false;
Mikhail Naganov289468a2023-03-29 10:06:15 -0700726 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
727 s, destinationPortIds, &portConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800728 if (created) {
729 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, portConfig.id);
730 }
731 ids->push_back(portConfig.id);
Mikhail Naganov289468a2023-03-29 10:06:15 -0700732 if (portIds != nullptr) {
733 portIds->insert(portConfig.portId);
734 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800735 }
736 return OK;
737 };
Mikhail Naganov289468a2023-03-29 10:06:15 -0700738 // When looking up port configs, the destinationPortId is only used for mix ports.
739 // Thus, we process device port configs first, and look up the destination port ID from them.
740 bool sourceIsDevice = std::any_of(aidlSources.begin(), aidlSources.end(),
741 [](const auto& config) { return config.ext.getTag() == AudioPortExt::device; });
742 const std::vector<AudioPortConfig>& devicePortConfigs =
743 sourceIsDevice ? aidlSources : aidlSinks;
744 std::vector<int32_t>* devicePortConfigIds =
745 sourceIsDevice ? &aidlPatch.sourcePortConfigIds : &aidlPatch.sinkPortConfigIds;
746 const std::vector<AudioPortConfig>& mixPortConfigs =
747 sourceIsDevice ? aidlSinks : aidlSources;
748 std::vector<int32_t>* mixPortConfigIds =
749 sourceIsDevice ? &aidlPatch.sinkPortConfigIds : &aidlPatch.sourcePortConfigIds;
750 std::set<int32_t> devicePortIds;
751 RETURN_STATUS_IF_ERROR(fillPortConfigs(
752 devicePortConfigs, std::set<int32_t>(), devicePortConfigIds, &devicePortIds));
753 RETURN_STATUS_IF_ERROR(fillPortConfigs(
754 mixPortConfigs, devicePortIds, mixPortConfigIds, nullptr));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800755 if (existingPatchIt != mPatches.end()) {
756 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
757 mModule->setAudioPatch(aidlPatch, &aidlPatch)));
758 existingPatchIt->second = aidlPatch;
759 } else {
760 bool created = false;
761 RETURN_STATUS_IF_ERROR(findOrCreatePatch(aidlPatch, &aidlPatch, &created));
762 // Since no cleanup of the patch is needed, 'created' is ignored.
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800763 halPatchId = aidlPatch.id;
764 *patch = static_cast<audio_patch_handle_t>(halPatchId);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800765 }
766 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000767 return OK;
768}
769
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800770status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800771 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000772 TIME_CHECK();
773 if (!mModule) return NO_INIT;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800774 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
775 if (patch == AUDIO_PATCH_HANDLE_NONE) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800776 return BAD_VALUE;
777 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800778 int32_t halPatchId = static_cast<int32_t>(patch);
779 auto patchIt = mPatches.find(halPatchId);
780 if (patchIt == mPatches.end()) {
781 ALOGE("%s: patch with id %d not found", __func__, halPatchId);
782 return BAD_VALUE;
783 }
784 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->resetAudioPatch(halPatchId)));
785 mPatches.erase(patchIt);
Shunkai Yao51202502022-12-12 06:11:46 +0000786 return OK;
787}
788
Mikhail Naganove93a0862023-03-15 17:06:59 -0700789status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
790 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000791 TIME_CHECK();
792 if (!mModule) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700793 if (port == nullptr) {
794 return BAD_VALUE;
795 }
796 audio_port_v7 portV7;
797 audio_populate_audio_port_v7(port, &portV7);
798 RETURN_STATUS_IF_ERROR(getAudioPort(&portV7));
799 return audio_populate_audio_port(&portV7, port) ? OK : BAD_VALUE;
800}
801
802status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
803 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
804 TIME_CHECK();
805 if (!mModule) return NO_INIT;
806 if (port == nullptr) {
807 return BAD_VALUE;
808 }
809 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
810 ::aidl::android::AudioPortDirection::INPUT;
811 auto aidlPort = VALUE_OR_RETURN_STATUS(
812 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
813 if (aidlPort.ext.getTag() != AudioPortExt::device) {
814 ALOGE("%s: provided port is not a device port (module %s): %s",
815 __func__, mInstance.c_str(), aidlPort.toString().c_str());
816 return BAD_VALUE;
817 }
818 const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
819 // It seems that we don't have to call HAL since all valid ports have been added either
820 // during initialization, or while handling connection of an external device.
821 auto portsIt = findPort(matchDevice);
822 if (portsIt == mPorts.end()) {
823 ALOGE("%s: device port for device %s is not found in the module %s",
824 __func__, matchDevice.toString().c_str(), mInstance.c_str());
825 return BAD_VALUE;
826 }
827 const int32_t fwkId = aidlPort.id;
828 aidlPort = portsIt->second;
829 aidlPort.id = fwkId;
830 *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
831 aidlPort, isInput));
832 return OK;
833}
834
835status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
836 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
837 TIME_CHECK();
838 if (!mModule) return NO_INIT;
839 if (config == nullptr) {
840 return BAD_VALUE;
841 }
842 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
843 config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
844 AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
845 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
846 *config, isInput, 0 /*portId*/));
847 AudioPortConfig portConfig;
848 bool created = false;
Mikhail Naganov289468a2023-03-29 10:06:15 -0700849 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
850 requestedPortConfig, std::set<int32_t>(), &portConfig, &created));
Shunkai Yao51202502022-12-12 06:11:46 +0000851 return OK;
852}
853
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800854MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
855 if (mMicrophones.status == Microphones::Status::UNKNOWN) {
856 TIME_CHECK();
857 std::vector<MicrophoneInfo> aidlInfo;
858 status_t status = statusTFromBinderStatus(mModule->getMicrophones(&aidlInfo));
859 if (status == OK) {
860 mMicrophones.status = Microphones::Status::QUERIED;
861 mMicrophones.info = std::move(aidlInfo);
862 } else if (status == INVALID_OPERATION) {
863 mMicrophones.status = Microphones::Status::NOT_SUPPORTED;
864 } else {
865 ALOGE("%s: Unexpected status from 'IModule.getMicrophones': %d", __func__, status);
866 return {};
867 }
868 }
869 if (mMicrophones.status == Microphones::Status::QUERIED) {
870 return &mMicrophones.info;
871 }
872 return {}; // NOT_SUPPORTED
873}
874
Shunkai Yao51202502022-12-12 06:11:46 +0000875status_t DeviceHalAidl::getMicrophones(
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800876 std::vector<audio_microphone_characteristic_t>* microphones) {
877 if (!microphones) {
878 return BAD_VALUE;
879 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000880 TIME_CHECK();
881 if (!mModule) return NO_INIT;
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800882 auto staticInfo = getMicrophoneInfo();
883 if (!staticInfo) return INVALID_OPERATION;
884 std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
885 emptyDynamicInfo.reserve(staticInfo->size());
886 std::transform(staticInfo->begin(), staticInfo->end(), std::back_inserter(emptyDynamicInfo),
887 [](const auto& info) { return MicrophoneDynamicInfo{ .id = info.id }; });
888 *microphones = VALUE_OR_RETURN_STATUS(
889 ::aidl::android::convertContainers<std::vector<audio_microphone_characteristic_t>>(
890 *staticInfo, emptyDynamicInfo,
891 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t)
892 );
Shunkai Yao51202502022-12-12 06:11:46 +0000893 return OK;
894}
895
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700896status_t DeviceHalAidl::addDeviceEffect(
897 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
898 TIME_CHECK();
899 if (!mModule) return NO_INIT;
Shunkai Yao51202502022-12-12 06:11:46 +0000900 if (!effect) {
901 return BAD_VALUE;
902 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700903 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
904 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
905 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
906 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
907 *device, isInput, 0));
908 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
909 ALOGE("%s: provided port config is not a device port config: %s",
910 __func__, requestedPortConfig.toString().c_str());
911 return BAD_VALUE;
912 }
913 AudioPortConfig devicePortConfig;
914 bool created;
915 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
916 requestedPortConfig, {} /*destinationPortIds*/, &devicePortConfig, &created));
917 Cleanups cleanups;
918 if (created) {
919 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
920 }
921 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
922 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->addDeviceEffect(
923 devicePortConfig.id, aidlEffect->getIEffect())));
924 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000925 return OK;
926}
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700927status_t DeviceHalAidl::removeDeviceEffect(
928 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
929 TIME_CHECK();
930 if (!mModule) return NO_INIT;
Shunkai Yao51202502022-12-12 06:11:46 +0000931 if (!effect) {
932 return BAD_VALUE;
933 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700934 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
935 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
936 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
937 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
938 *device, isInput, 0));
939 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
940 ALOGE("%s: provided port config is not a device port config: %s",
941 __func__, requestedPortConfig.toString().c_str());
942 return BAD_VALUE;
943 }
944 auto existingPortConfigIt = findPortConfig(
945 requestedPortConfig.ext.get<AudioPortExt::Tag::device>().device);
946 if (existingPortConfigIt == mPortConfigs.end()) {
947 ALOGE("%s: could not find a configured device port for the config %s",
948 __func__, requestedPortConfig.toString().c_str());
949 return BAD_VALUE;
950 }
951 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
952 return statusTFromBinderStatus(mModule->removeDeviceEffect(
953 existingPortConfigIt->first, aidlEffect->getIEffect()));
Shunkai Yao51202502022-12-12 06:11:46 +0000954}
955
956status_t DeviceHalAidl::getMmapPolicyInfos(
David Li9cf5e622023-03-21 00:51:10 +0800957 media::audio::common::AudioMMapPolicyType policyType,
958 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000959 TIME_CHECK();
Mikhail Naganov25bc9a22023-04-21 18:48:16 -0700960 AudioMMapPolicyType mmapPolicyType = VALUE_OR_RETURN_STATUS(
961 cpp2ndk_AudioMMapPolicyType(policyType));
David Li9cf5e622023-03-21 00:51:10 +0800962
963 std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
964
965 if (status_t status = statusTFromBinderStatus(
966 mModule->getMmapPolicyInfos(mmapPolicyType, &mmapPolicyInfos)); status != OK) {
967 return status;
968 }
969
970 *policyInfos = VALUE_OR_RETURN_STATUS(
971 convertContainer<std::vector<media::audio::common::AudioMMapPolicyInfo>>(
972 mmapPolicyInfos, ndk2cpp_AudioMMapPolicyInfo));
Shunkai Yao51202502022-12-12 06:11:46 +0000973 return OK;
974}
975
976int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000977 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800978 int32_t mixerBurstCount = 0;
979 if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
980 return mixerBurstCount;
981 }
982 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000983}
984
985int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000986 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800987 int32_t hardwareBurstMinUsec = 0;
988 if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
989 return hardwareBurstMinUsec;
990 }
991 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000992}
993
994error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000995 TIME_CHECK();
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700996 if (!mModule) return NO_INIT;
997 int32_t aidlHwAvSync;
998 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
999 return VALUE_OR_RETURN_STATUS(
1000 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +00001001}
1002
Mikhail Naganovfab697c2023-01-11 19:33:13 +00001003status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
1004 TIME_CHECK();
1005 if (!mModule) return NO_INIT;
1006 return mModule->dump(fd, Args(args).args(), args.size());
David Li9cf5e622023-03-21 00:51:10 +08001007}
Shunkai Yao51202502022-12-12 06:11:46 +00001008
Mikhail Naganov3ac95c92023-04-12 13:14:30 -07001009int32_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
Mikhail Naganov31d46652023-01-10 18:29:25 +00001010 TIME_CHECK();
Mikhail Naganov3ac95c92023-04-12 13:14:30 -07001011 if (!mModule) return NO_INIT;
1012 if (supports == nullptr) {
1013 return BAD_VALUE;
1014 }
1015 return statusTFromBinderStatus(mModule->supportsVariableLatency(supports));
Shunkai Yao51202502022-12-12 06:11:46 +00001016}
Mikhail Naganov31d46652023-01-10 18:29:25 +00001017
jiabin872de702023-04-27 22:04:31 +00001018
1019status_t DeviceHalAidl::prepareToDisconnectExternalDevice(const struct audio_port_v7* port) {
1020 // There is not AIDL API defined for `prepareToDisconnectExternalDevice`.
1021 // Call `setConnectedState` instead.
1022 // TODO(b/279824103): call prepareToDisconnectExternalDevice when it is added.
1023 const status_t status = setConnectedState(port, false /*connected*/);
1024 if (status == NO_ERROR) {
1025 mDeviceDisconnectionNotified.insert(port->id);
1026 }
1027 return status;
1028}
1029
Mikhail Naganove93a0862023-03-15 17:06:59 -07001030status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
1031 TIME_CHECK();
1032 if (!mModule) return NO_INIT;
1033 if (port == nullptr) {
1034 return BAD_VALUE;
1035 }
jiabin872de702023-04-27 22:04:31 +00001036 if (!connected && mDeviceDisconnectionNotified.erase(port->id) > 0) {
1037 // For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
1038 // and then call `setConnectedState`. However, there is no API for
1039 // `prepareToDisconnectExternalDevice` yet. In that case, `setConnectedState` will be
1040 // called when calling `prepareToDisconnectExternalDevice`. Do not call to the HAL if
1041 // previous call is successful. Also remove the cache here to avoid a large cache after
1042 // a long run.
1043 return NO_ERROR;
1044 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001045 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
1046 ::aidl::android::AudioPortDirection::INPUT;
1047 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
1048 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
1049 if (aidlPort.ext.getTag() != AudioPortExt::device) {
1050 ALOGE("%s: provided port is not a device port (module %s): %s",
1051 __func__, mInstance.c_str(), aidlPort.toString().c_str());
1052 return BAD_VALUE;
1053 }
1054 if (connected) {
1055 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1056 // Reset the device address to find the "template" port.
1057 matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
1058 auto portsIt = findPort(matchDevice);
1059 if (portsIt == mPorts.end()) {
Mikhail Naganov69557132023-09-07 15:29:01 -07001060 // Since 'setConnectedState' is called for all modules, it is normal when the device
1061 // port not found in every one of them.
1062 ALOGD("%s: device port for device %s is not found in the module %s",
Mikhail Naganove93a0862023-03-15 17:06:59 -07001063 __func__, matchDevice.toString().c_str(), mInstance.c_str());
1064 return BAD_VALUE;
1065 }
1066 // Use the ID of the "template" port, use all the information from the provided port.
1067 aidlPort.id = portsIt->first;
1068 AudioPort connectedPort;
1069 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
1070 aidlPort, &connectedPort)));
1071 const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
1072 LOG_ALWAYS_FATAL_IF(!inserted,
1073 "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
1074 __func__, mInstance.c_str(), connectedPort.toString().c_str(),
1075 it->second.toString().c_str());
1076 } else { // !connected
1077 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1078 auto portsIt = findPort(matchDevice);
1079 if (portsIt == mPorts.end()) {
1080 ALOGW("%s: device port for device %s is not found in the module %s",
1081 __func__, matchDevice.toString().c_str(), mInstance.c_str());
1082 return BAD_VALUE;
1083 }
1084 // Any streams opened on the external device must be closed by this time,
1085 // thus we can clean up patches and port configs that were created for them.
1086 resetUnusedPatchesAndPortConfigs();
1087 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
1088 portsIt->second.id)));
1089 mPorts.erase(portsIt);
1090 }
Mikhail Naganov289468a2023-03-29 10:06:15 -07001091 return updateRoutes();
Mikhail Naganove93a0862023-03-15 17:06:59 -07001092}
1093
1094status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
1095 TIME_CHECK();
1096 if (!mModule) return NO_INIT;
1097 ModuleDebug debug{ .simulateDeviceConnections = enabled };
1098 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
1099 // This is important to log as it affects HAL behavior.
1100 if (status == OK) {
1101 ALOGI("%s: set enabled: %d", __func__, enabled);
1102 } else {
1103 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
1104 }
1105 return status;
1106}
1107
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001108bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
1109 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1110 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1111}
1112
1113bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
1114 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1115 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1116 return p.portId == mDefaultInputPortId;
1117 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1118 return p.portId == mDefaultOutputPortId;
1119 }
1120 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1121}
1122
David Lia8675d42023-03-30 21:08:06 +08001123status_t DeviceHalAidl::createOrUpdatePortConfig(
1124 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool* created) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001125 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001126 AudioPortConfig appliedPortConfig;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001127 bool applied = false;
1128 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001129 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001130 if (!applied) {
1131 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001132 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001133 if (!applied) {
1134 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001135 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001136 return NO_INIT;
1137 }
1138 }
David Lia8675d42023-03-30 21:08:06 +08001139
1140 int32_t id = appliedPortConfig.id;
1141 if (requestedPortConfig.id != 0 && requestedPortConfig.id != id) {
1142 LOG_ALWAYS_FATAL("%s: requested port config id %d changed to %d", __func__,
1143 requestedPortConfig.id, id);
1144 }
1145
1146 auto [it, inserted] = mPortConfigs.insert_or_assign(std::move(id),
1147 std::move(appliedPortConfig));
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001148 *result = it;
David Lia8675d42023-03-30 21:08:06 +08001149 *created = inserted;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001150 return OK;
1151}
1152
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001153status_t DeviceHalAidl::filterAndRetrieveBtA2dpParameters(
1154 AudioParameter &keys, AudioParameter *result) {
1155 TIME_CHECK();
1156 if (String8 key = String8(AudioParameter::keyReconfigA2dpSupported); keys.containsKey(key)) {
1157 keys.remove(key);
1158 bool supports;
1159 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1160 mBluetoothA2dp->supportsOffloadReconfiguration(&supports)));
1161 result->addInt(key, supports ? 1 : 0);
1162 }
1163 return OK;
1164}
1165
Mikhail Naganovccc82112023-04-27 18:14:15 -07001166status_t DeviceHalAidl::filterAndUpdateBtA2dpParameters(AudioParameter &parameters) {
1167 TIME_CHECK();
1168 std::optional<bool> a2dpEnabled;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001169 std::optional<std::vector<VendorParameter>> reconfigureOffload;
Mikhail Naganovccc82112023-04-27 18:14:15 -07001170 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1171 parameters, String8(AudioParameter::keyBtA2dpSuspended),
1172 [&a2dpEnabled](const String8& trueOrFalse) {
1173 if (trueOrFalse == AudioParameter::valueTrue) {
1174 a2dpEnabled = false; // 'suspended' == true
1175 return OK;
1176 } else if (trueOrFalse == AudioParameter::valueFalse) {
1177 a2dpEnabled = true; // 'suspended' == false
1178 return OK;
1179 }
1180 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1181 AudioParameter::keyBtA2dpSuspended, trueOrFalse.c_str());
1182 return BAD_VALUE;
1183 }));
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001184 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1185 parameters, String8(AudioParameter::keyReconfigA2dp),
1186 [&](const String8& value) -> status_t {
1187 if (mVendorExt != nullptr) {
1188 std::vector<VendorParameter> result;
1189 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1190 mVendorExt->parseBluetoothA2dpReconfigureOffload(
1191 std::string(value.c_str()), &result)));
1192 reconfigureOffload = std::move(result);
1193 } else {
1194 reconfigureOffload = std::vector<VendorParameter>();
1195 }
1196 return OK;
1197 }));
Mikhail Naganovccc82112023-04-27 18:14:15 -07001198 if (mBluetoothA2dp != nullptr && a2dpEnabled.has_value()) {
1199 return statusTFromBinderStatus(mBluetoothA2dp->setEnabled(a2dpEnabled.value()));
1200 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001201 if (mBluetoothA2dp != nullptr && reconfigureOffload.has_value()) {
1202 return statusTFromBinderStatus(mBluetoothA2dp->reconfigureOffload(
1203 reconfigureOffload.value()));
1204 }
Mikhail Naganovccc82112023-04-27 18:14:15 -07001205 return OK;
1206}
1207
1208status_t DeviceHalAidl::filterAndUpdateBtHfpParameters(AudioParameter &parameters) {
1209 TIME_CHECK();
1210 IBluetooth::HfpConfig hfpConfig;
1211 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1212 parameters, String8(AudioParameter::keyBtHfpEnable),
1213 [&hfpConfig](const String8& trueOrFalse) {
1214 if (trueOrFalse == AudioParameter::valueTrue) {
1215 hfpConfig.isEnabled = Boolean{ .value = true };
1216 return OK;
1217 } else if (trueOrFalse == AudioParameter::valueFalse) {
1218 hfpConfig.isEnabled = Boolean{ .value = false };
1219 return OK;
1220 }
1221 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1222 AudioParameter::keyBtHfpEnable, trueOrFalse.c_str());
1223 return BAD_VALUE;
1224 }));
1225 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1226 parameters, String8(AudioParameter::keyBtHfpSamplingRate),
1227 [&hfpConfig](int sampleRate) {
1228 return sampleRate > 0 ?
1229 hfpConfig.sampleRate = Int{ .value = sampleRate }, OK : BAD_VALUE;
1230 }));
1231 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1232 parameters, String8(AudioParameter::keyBtHfpVolume),
1233 [&hfpConfig](int volume0to15) {
1234 if (volume0to15 >= 0 && volume0to15 <= 15) {
1235 hfpConfig.volume = Float{ .value = volume0to15 / 15.0f };
1236 return OK;
1237 }
1238 return BAD_VALUE;
1239 }));
1240 if (mBluetooth != nullptr && hfpConfig != IBluetooth::HfpConfig{}) {
1241 IBluetooth::HfpConfig newHfpConfig;
1242 return statusTFromBinderStatus(mBluetooth->setHfpConfig(hfpConfig, &newHfpConfig));
1243 }
1244 return OK;
1245}
1246
1247status_t DeviceHalAidl::filterAndUpdateBtLeParameters(AudioParameter &parameters) {
1248 TIME_CHECK();
1249 std::optional<bool> leEnabled;
1250 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1251 parameters, String8(AudioParameter::keyBtLeSuspended),
1252 [&leEnabled](const String8& trueOrFalse) {
1253 if (trueOrFalse == AudioParameter::valueTrue) {
1254 leEnabled = false; // 'suspended' == true
1255 return OK;
1256 } else if (trueOrFalse == AudioParameter::valueFalse) {
1257 leEnabled = true; // 'suspended' == false
1258 return OK;
1259 }
1260 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1261 AudioParameter::keyBtLeSuspended, trueOrFalse.c_str());
1262 return BAD_VALUE;
1263 }));
1264 if (mBluetoothLe != nullptr && leEnabled.has_value()) {
1265 return statusTFromBinderStatus(mBluetoothLe->setEnabled(leEnabled.value()));
1266 }
1267 return OK;
1268}
1269
1270status_t DeviceHalAidl::filterAndUpdateBtScoParameters(AudioParameter &parameters) {
1271 TIME_CHECK();
1272 IBluetooth::ScoConfig scoConfig;
1273 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1274 parameters, String8(AudioParameter::keyBtSco),
1275 [&scoConfig](const String8& onOrOff) {
1276 if (onOrOff == AudioParameter::valueOn) {
1277 scoConfig.isEnabled = Boolean{ .value = true };
1278 return OK;
1279 } else if (onOrOff == AudioParameter::valueOff) {
1280 scoConfig.isEnabled = Boolean{ .value = false };
1281 return OK;
1282 }
1283 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1284 AudioParameter::keyBtSco, onOrOff.c_str());
1285 return BAD_VALUE;
1286 }));
1287 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1288 parameters, String8(AudioParameter::keyBtScoHeadsetName),
1289 [&scoConfig](const String8& name) {
1290 scoConfig.debugName = name;
1291 return OK;
1292 }));
1293 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1294 parameters, String8(AudioParameter::keyBtNrec),
1295 [&scoConfig](const String8& onOrOff) {
1296 if (onOrOff == AudioParameter::valueOn) {
1297 scoConfig.isNrecEnabled = Boolean{ .value = true };
1298 return OK;
1299 } else if (onOrOff == AudioParameter::valueOff) {
1300 scoConfig.isNrecEnabled = Boolean{ .value = false };
1301 return OK;
1302 }
1303 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1304 AudioParameter::keyBtNrec, onOrOff.c_str());
1305 return BAD_VALUE;
1306 }));
1307 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1308 parameters, String8(AudioParameter::keyBtScoWb),
1309 [&scoConfig](const String8& onOrOff) {
1310 if (onOrOff == AudioParameter::valueOn) {
1311 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO_WB;
1312 return OK;
1313 } else if (onOrOff == AudioParameter::valueOff) {
1314 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO;
1315 return OK;
1316 }
1317 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1318 AudioParameter::keyBtScoWb, onOrOff.c_str());
1319 return BAD_VALUE;
1320 }));
1321 if (mBluetooth != nullptr && scoConfig != IBluetooth::ScoConfig{}) {
1322 IBluetooth::ScoConfig newScoConfig;
1323 return statusTFromBinderStatus(mBluetooth->setScoConfig(scoConfig, &newScoConfig));
1324 }
1325 return OK;
1326}
1327
Mikhail Naganove92c34b2023-05-31 14:24:48 -07001328status_t DeviceHalAidl::filterAndUpdateScreenParameters(AudioParameter &parameters) {
1329 TIME_CHECK();
1330 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1331 parameters, String8(AudioParameter::keyScreenState),
1332 [&](const String8& onOrOff) -> status_t {
1333 std::optional<bool> isTurnedOn;
1334 if (onOrOff == AudioParameter::valueOn) {
1335 isTurnedOn = true;
1336 } else if (onOrOff == AudioParameter::valueOff) {
1337 isTurnedOn = false;
1338 }
1339 if (!isTurnedOn.has_value()) {
1340 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1341 AudioParameter::keyScreenState, onOrOff.c_str());
1342 return BAD_VALUE;
1343 }
1344 return statusTFromBinderStatus(
1345 mModule->updateScreenState(isTurnedOn.value()));
1346 }));
1347 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1348 parameters, String8(AudioParameter::keyScreenRotation),
1349 [&](int rotationDegrees) -> status_t {
1350 IModule::ScreenRotation rotation;
1351 switch (rotationDegrees) {
1352 case 0: rotation = IModule::ScreenRotation::DEG_0; break;
1353 case 90: rotation = IModule::ScreenRotation::DEG_90; break;
1354 case 180: rotation = IModule::ScreenRotation::DEG_180; break;
1355 case 270: rotation = IModule::ScreenRotation::DEG_270; break;
1356 default:
1357 ALOGE("setParameters: parameter key \"%s\" has invalid value %d",
1358 AudioParameter::keyScreenRotation, rotationDegrees);
1359 return BAD_VALUE;
1360 }
1361 return statusTFromBinderStatus(mModule->updateScreenRotation(rotation));
1362 }));
1363 return OK;
1364}
1365
Mikhail Naganovb9a81312023-07-18 13:55:34 -07001366status_t DeviceHalAidl::filterAndUpdateTelephonyParameters(AudioParameter &parameters) {
1367 TIME_CHECK();
1368 using TtyMode = ITelephony::TelecomConfig::TtyMode;
1369 ITelephony::TelecomConfig telConfig;
1370 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1371 parameters, String8(AudioParameter::keyTtyMode),
1372 [&telConfig](const String8& mode) {
1373 if (mode == AudioParameter::valueTtyModeOff) {
1374 telConfig.ttyMode = TtyMode::OFF;
1375 return OK;
1376 } else if (mode == AudioParameter::valueTtyModeFull) {
1377 telConfig.ttyMode = TtyMode::FULL;
1378 return OK;
1379 } else if (mode == AudioParameter::valueTtyModeHco) {
1380 telConfig.ttyMode = TtyMode::HCO;
1381 return OK;
1382 } else if (mode == AudioParameter::valueTtyModeVco) {
1383 telConfig.ttyMode = TtyMode::VCO;
1384 return OK;
1385 }
1386 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1387 AudioParameter::keyTtyMode, mode.c_str());
1388 return BAD_VALUE;
1389 }));
1390 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1391 parameters, String8(AudioParameter::keyHacSetting),
1392 [&telConfig](const String8& onOrOff) {
1393 if (onOrOff == AudioParameter::valueHacOn) {
1394 telConfig.isHacEnabled = Boolean{ .value = true };
1395 return OK;
1396 } else if (onOrOff == AudioParameter::valueHacOff) {
1397 telConfig.isHacEnabled = Boolean{ .value = false };
1398 return OK;
1399 }
1400 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1401 AudioParameter::keyHacSetting, onOrOff.c_str());
1402 return BAD_VALUE;
1403 }));
1404 if (mTelephony != nullptr && telConfig != ITelephony::TelecomConfig{}) {
1405 ITelephony::TelecomConfig newTelConfig;
1406 return statusTFromBinderStatus(
1407 mTelephony->setTelecomConfig(telConfig, &newTelConfig));
1408 }
1409 return OK;
1410}
1411
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001412status_t DeviceHalAidl::findOrCreatePatch(
1413 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
1414 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
1415 requestedPatch.sourcePortConfigIds.end());
1416 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
1417 requestedPatch.sinkPortConfigIds.end());
1418 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
1419}
1420
1421status_t DeviceHalAidl::findOrCreatePatch(
1422 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
1423 AudioPatch* patch, bool* created) {
1424 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
1425 if (patchIt == mPatches.end()) {
1426 TIME_CHECK();
1427 AudioPatch requestedPatch, appliedPatch;
1428 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
1429 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
1430 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
1431 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
1432 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
1433 requestedPatch, &appliedPatch)));
1434 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
1435 *created = true;
1436 } else {
1437 *created = false;
1438 }
1439 *patch = patchIt->second;
1440 return OK;
1441}
1442
jiabin9c07faf2023-04-26 22:00:44 +00001443status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device, const AudioConfig* config,
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001444 AudioPortConfig* portConfig, bool* created) {
1445 auto portConfigIt = findPortConfig(device);
1446 if (portConfigIt == mPortConfigs.end()) {
1447 auto portsIt = findPort(device);
1448 if (portsIt == mPorts.end()) {
1449 ALOGE("%s: device port for device %s is not found in the module %s",
1450 __func__, device.toString().c_str(), mInstance.c_str());
1451 return BAD_VALUE;
1452 }
1453 AudioPortConfig requestedPortConfig;
1454 requestedPortConfig.portId = portsIt->first;
jiabin9c07faf2023-04-26 22:00:44 +00001455 if (config != nullptr) {
1456 setPortConfigFromConfig(&requestedPortConfig, *config);
1457 }
David Lia8675d42023-03-30 21:08:06 +08001458 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1459 created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001460 } else {
1461 *created = false;
1462 }
1463 *portConfig = portConfigIt->second;
1464 return OK;
1465}
1466
1467status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001468 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001469 AudioSource source, const std::set<int32_t>& destinationPortIds,
1470 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001471 // These flags get removed one by one in this order when retrying port finding.
1472 static const std::vector<AudioInputFlags> kOptionalInputFlags{
1473 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001474 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001475 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001476 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
1477 AudioIoFlags matchFlags = flags.value();
Mikhail Naganov289468a2023-03-29 10:06:15 -07001478 auto portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001479 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
1480 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
1481 if (!isBitPositionFlagSet(
1482 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
1483 ++optionalInputFlagsIt;
1484 continue;
1485 }
1486 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
1487 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
Mikhail Naganov289468a2023-03-29 10:06:15 -07001488 portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001489 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
1490 "retried with flags %s", __func__, config.toString().c_str(),
1491 flags.value().toString().c_str(), mInstance.c_str(),
1492 matchFlags.toString().c_str());
1493 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001494 if (portsIt == mPorts.end()) {
1495 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001496 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001497 mInstance.c_str());
1498 return BAD_VALUE;
1499 }
1500 AudioPortConfig requestedPortConfig;
1501 requestedPortConfig.portId = portsIt->first;
1502 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001503 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001504 if (matchFlags.getTag() == AudioIoFlags::Tag::input
1505 && source != AudioSource::SYS_RESERVED_INVALID) {
1506 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
1507 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
1508 }
David Lia8675d42023-03-30 21:08:06 +08001509 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1510 created));
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001511 } else if (!flags.has_value()) {
1512 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
1513 "and was not created as flags are not specified",
1514 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
1515 return BAD_VALUE;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001516 } else {
David Lia8675d42023-03-30 21:08:06 +08001517 AudioPortConfig requestedPortConfig = portConfigIt->second;
1518 if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
1519 AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
1520 if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
1521 source != AudioSource::SYS_RESERVED_INVALID) {
1522 mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
1523 }
1524 }
1525
1526 if (requestedPortConfig != portConfigIt->second) {
1527 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1528 created));
1529 } else {
1530 *created = false;
1531 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001532 }
1533 *portConfig = portConfigIt->second;
1534 return OK;
1535}
1536
1537status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001538 const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
1539 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001540 using Tag = AudioPortExt::Tag;
1541 if (requestedPortConfig.ext.getTag() == Tag::mix) {
1542 if (const auto& p = requestedPortConfig;
1543 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001544 !p.format.has_value()) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001545 ALOGW("%s: provided mix port config is not fully specified: %s",
1546 __func__, p.toString().c_str());
1547 return BAD_VALUE;
1548 }
1549 AudioConfig config;
1550 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001551 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
1552 AudioPortMixExtUseCase::Tag::source ?
1553 requestedPortConfig.ext.get<Tag::mix>().usecase.
1554 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001555 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001556 requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
1557 portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001558 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
1559 return findOrCreatePortConfig(
jiabin9c07faf2023-04-26 22:00:44 +00001560 requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
1561 portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001562 }
1563 ALOGW("%s: unsupported audio port config: %s",
1564 __func__, requestedPortConfig.toString().c_str());
1565 return BAD_VALUE;
1566}
1567
1568DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
1569 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
1570 return std::find_if(mPatches.begin(), mPatches.end(),
1571 [&](const auto& pair) {
1572 const auto& p = pair.second;
1573 std::set<int32_t> patchSrcs(
1574 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
1575 std::set<int32_t> patchSinks(
1576 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
1577 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
1578}
1579
1580DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001581 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1582 return mPorts.find(mDefaultInputPortId);
1583 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1584 return mPorts.find(mDefaultOutputPortId);
1585 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001586 return std::find_if(mPorts.begin(), mPorts.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001587 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001588}
1589
1590DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001591 const AudioConfig& config, const AudioIoFlags& flags,
1592 const std::set<int32_t>& destinationPortIds) {
Mikhail Naganove93a0862023-03-15 17:06:59 -07001593 auto belongsToProfile = [&config](const AudioProfile& prof) {
1594 return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
1595 (config.base.channelMask.getTag() == AudioChannelLayout::none ||
1596 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
1597 config.base.channelMask) != prof.channelMasks.end()) &&
1598 (config.base.sampleRate == 0 ||
1599 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
1600 config.base.sampleRate) != prof.sampleRates.end());
1601 };
jiabin9c07faf2023-04-26 22:00:44 +00001602 static const std::vector<AudioOutputFlags> kOptionalOutputFlags{AudioOutputFlags::BIT_PERFECT};
1603 int optionalFlags = 0;
1604 auto flagMatches = [&flags, &optionalFlags](const AudioIoFlags& portFlags) {
1605 // Ports should be able to match if the optional flags are not requested.
1606 return portFlags == flags ||
1607 (portFlags.getTag() == AudioIoFlags::Tag::output &&
1608 AudioIoFlags::make<AudioIoFlags::Tag::output>(
1609 portFlags.get<AudioIoFlags::Tag::output>() &
1610 ~optionalFlags) == flags);
1611 };
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001612 auto matcher = [&](const auto& pair) {
1613 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001614 return p.ext.getTag() == AudioPortExt::Tag::mix &&
jiabin9c07faf2023-04-26 22:00:44 +00001615 flagMatches(p.flags) &&
Mikhail Naganov289468a2023-03-29 10:06:15 -07001616 (destinationPortIds.empty() ||
1617 std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
1618 [&](const int32_t destId) { return mRoutingMatrix.count(
1619 std::make_pair(p.id, destId)) != 0; })) &&
Mikhail Naganove93a0862023-03-15 17:06:59 -07001620 (p.profiles.empty() ||
1621 std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
1622 p.profiles.end()); };
jiabin9c07faf2023-04-26 22:00:44 +00001623 auto result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1624 if (result == mPorts.end() && flags.getTag() == AudioIoFlags::Tag::output) {
1625 auto optionalOutputFlagsIt = kOptionalOutputFlags.begin();
1626 while (result == mPorts.end() && optionalOutputFlagsIt != kOptionalOutputFlags.end()) {
1627 if (isBitPositionFlagSet(
1628 flags.get<AudioIoFlags::Tag::output>(), *optionalOutputFlagsIt)) {
1629 // If the flag is set by the request, it must be matched.
1630 ++optionalOutputFlagsIt;
1631 continue;
1632 }
1633 optionalFlags |= makeBitPositionFlagMask(*optionalOutputFlagsIt++);
1634 result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1635 ALOGI("%s: port for config %s, flags %s was not found in the module %s, "
1636 "retried with excluding optional flags %#x", __func__, config.toString().c_str(),
1637 flags.toString().c_str(), mInstance.c_str(), optionalFlags);
1638 }
1639 }
1640 return result;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001641}
1642
1643DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001644 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001645 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001646}
1647
1648DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001649 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001650 using Tag = AudioPortExt::Tag;
1651 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
1652 [&](const auto& pair) {
1653 const auto& p = pair.second;
1654 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
1655 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
1656 !p.format.has_value() || !p.flags.has_value(),
1657 "%s: stored mix port config is not fully specified: %s",
1658 __func__, p.toString().c_str());
1659 return p.ext.getTag() == Tag::mix &&
1660 isConfigEqualToPortConfig(config, p) &&
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001661 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001662 p.ext.template get<Tag::mix>().handle == ioHandle; });
1663}
Mikhail Naganove93a0862023-03-15 17:06:59 -07001664
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001665void DeviceHalAidl::resetPatch(int32_t patchId) {
1666 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1667 mPatches.erase(it);
1668 TIME_CHECK();
1669 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1670 ALOGE("%s: error while resetting patch %d: %s",
1671 __func__, patchId, status.getDescription().c_str());
1672 }
1673 return;
1674 }
1675 ALOGE("%s: patch id %d not found", __func__, patchId);
1676}
1677
1678void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1679 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1680 mPortConfigs.erase(it);
1681 TIME_CHECK();
1682 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1683 !status.isOk()) {
1684 ALOGE("%s: error while resetting port config %d: %s",
1685 __func__, portConfigId, status.getDescription().c_str());
1686 }
1687 return;
1688 }
1689 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1690}
1691
Mikhail Naganove93a0862023-03-15 17:06:59 -07001692void DeviceHalAidl::resetUnusedPatches() {
1693 // Since patches can be created independently of streams via 'createAudioPatch',
1694 // here we only clean up patches for released streams.
1695 for (auto it = mStreams.begin(); it != mStreams.end(); ) {
1696 if (auto streamSp = it->first.promote(); streamSp) {
1697 ++it;
1698 } else {
1699 resetPatch(it->second);
1700 it = mStreams.erase(it);
1701 }
1702 }
1703}
1704
1705void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
1706 resetUnusedPatches();
1707 resetUnusedPortConfigs();
1708}
1709
1710void DeviceHalAidl::resetUnusedPortConfigs() {
1711 // The assumption is that port configs are used to create patches
1712 // (or to open streams, but that involves creation of patches, too). Thus,
1713 // orphaned port configs can and should be reset.
1714 std::set<int32_t> portConfigIds;
1715 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
1716 std::inserter(portConfigIds, portConfigIds.end()),
1717 [](const auto& pcPair) { return pcPair.first; });
1718 for (const auto& p : mPatches) {
1719 for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
1720 for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
1721 }
jiabin9c07faf2023-04-26 22:00:44 +00001722 for (int32_t id : mInitialPortConfigIds) {
1723 portConfigIds.erase(id);
1724 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001725 for (int32_t id : portConfigIds) resetPortConfig(id);
1726}
1727
Mikhail Naganov289468a2023-03-29 10:06:15 -07001728status_t DeviceHalAidl::updateRoutes() {
1729 TIME_CHECK();
Mikhail Naganov289468a2023-03-29 10:06:15 -07001730 RETURN_STATUS_IF_ERROR(
Mikhail Naganovf83b9742023-04-24 13:06:04 -07001731 statusTFromBinderStatus(mModule->getAudioRoutes(&mRoutes)));
1732 ALOGW_IF(mRoutes.empty(), "%s: module %s returned an empty list of audio routes",
Mikhail Naganov289468a2023-03-29 10:06:15 -07001733 __func__, mInstance.c_str());
1734 mRoutingMatrix.clear();
Mikhail Naganovf83b9742023-04-24 13:06:04 -07001735 for (const auto& r : mRoutes) {
Mikhail Naganov289468a2023-03-29 10:06:15 -07001736 for (auto portId : r.sourcePortIds) {
1737 mRoutingMatrix.emplace(r.sinkPortId, portId);
1738 mRoutingMatrix.emplace(portId, r.sinkPortId);
1739 }
1740 }
1741 return OK;
1742}
1743
Mikhail Naganovdfd594e2023-02-08 16:59:41 -08001744void DeviceHalAidl::clearCallbacks(void* cookie) {
1745 std::lock_guard l(mLock);
1746 mCallbacks.erase(cookie);
1747}
1748
1749sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1750 return getCallbackImpl(cookie, &Callbacks::out);
1751}
1752
1753void DeviceHalAidl::setStreamOutCallback(
1754 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1755 setCallbackImpl(cookie, &Callbacks::out, cb);
1756}
1757
1758sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1759 void* cookie) {
1760 return getCallbackImpl(cookie, &Callbacks::event);
1761}
1762
1763void DeviceHalAidl::setStreamOutEventCallback(
1764 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1765 setCallbackImpl(cookie, &Callbacks::event, cb);
1766}
1767
1768sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1769 void* cookie) {
1770 return getCallbackImpl(cookie, &Callbacks::latency);
1771}
1772
1773void DeviceHalAidl::setStreamOutLatencyModeCallback(
1774 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1775 setCallbackImpl(cookie, &Callbacks::latency, cb);
1776}
1777
1778template<class C>
1779sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1780 std::lock_guard l(mLock);
1781 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1782 return ((it->second).*field).promote();
1783 }
1784 return nullptr;
1785}
1786template<class C>
1787void DeviceHalAidl::setCallbackImpl(
1788 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1789 std::lock_guard l(mLock);
1790 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1791 (it->second).*field = cb;
1792 }
1793}
1794
Mikhail Naganov31d46652023-01-10 18:29:25 +00001795} // namespace android