blob: c911ac8eb53716bf2ba15703e76697e7f45784eb [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 Naganove93a0862023-03-15 17:06:59 -070045using aidl::android::media::audio::common::AudioFormatType;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080046using aidl::android::media::audio::common::AudioInputFlags;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080047using aidl::android::media::audio::common::AudioIoFlags;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -080048using aidl::android::media::audio::common::AudioLatencyMode;
David Li9cf5e622023-03-21 00:51:10 +080049using aidl::android::media::audio::common::AudioMMapPolicy;
50using aidl::android::media::audio::common::AudioMMapPolicyInfo;
51using aidl::android::media::audio::common::AudioMMapPolicyType;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000052using aidl::android::media::audio::common::AudioMode;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080053using aidl::android::media::audio::common::AudioOutputFlags;
54using aidl::android::media::audio::common::AudioPort;
55using aidl::android::media::audio::common::AudioPortConfig;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080056using aidl::android::media::audio::common::AudioPortDeviceExt;
David Li9cf5e622023-03-21 00:51:10 +080057using aidl::android::media::audio::common::AudioPortExt;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -080058using aidl::android::media::audio::common::AudioPortMixExt;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -080059using aidl::android::media::audio::common::AudioPortMixExtUseCase;
Mikhail Naganove93a0862023-03-15 17:06:59 -070060using aidl::android::media::audio::common::AudioProfile;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080061using aidl::android::media::audio::common::AudioSource;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000062using aidl::android::media::audio::common::Float;
David Li9cf5e622023-03-21 00:51:10 +080063using aidl::android::media::audio::common::Int;
64using aidl::android::media::audio::common::MicrophoneDynamicInfo;
65using aidl::android::media::audio::common::MicrophoneInfo;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -070066using aidl::android::media::audio::IHalAdapterVendorExtension;
Mikhail Naganov6352e822023-03-09 18:22:36 -080067using aidl::android::hardware::audio::common::getFrameSizeInBytes;
68using aidl::android::hardware::audio::common::isBitPositionFlagSet;
Mikhail Naganove93a0862023-03-15 17:06:59 -070069using aidl::android::hardware::audio::common::isDefaultAudioFormat;
Mikhail Naganov6352e822023-03-09 18:22:36 -080070using aidl::android::hardware::audio::common::makeBitPositionFlagMask;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080071using aidl::android::hardware::audio::common::RecordTrackMetadata;
72using aidl::android::hardware::audio::core::AudioPatch;
Mikhail Naganov289468a2023-03-29 10:06:15 -070073using aidl::android::hardware::audio::core::AudioRoute;
Mikhail Naganovccc82112023-04-27 18:14:15 -070074using aidl::android::hardware::audio::core::IBluetooth;
75using aidl::android::hardware::audio::core::IBluetoothA2dp;
76using aidl::android::hardware::audio::core::IBluetoothLe;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000077using aidl::android::hardware::audio::core::IModule;
78using aidl::android::hardware::audio::core::ITelephony;
Mikhail Naganove93a0862023-03-15 17:06:59 -070079using aidl::android::hardware::audio::core::ModuleDebug;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000080using aidl::android::hardware::audio::core::StreamDescriptor;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -070081using aidl::android::hardware::audio::core::VendorParameter;
Mikhail Naganov31d46652023-01-10 18:29:25 +000082
83namespace android {
84
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080085namespace {
86
87bool isConfigEqualToPortConfig(const AudioConfig& config, const AudioPortConfig& portConfig) {
88 return portConfig.sampleRate.value().value == config.base.sampleRate &&
89 portConfig.channelMask.value() == config.base.channelMask &&
90 portConfig.format.value() == config.base.format;
91}
92
93void setConfigFromPortConfig(AudioConfig* config, const AudioPortConfig& portConfig) {
94 config->base.sampleRate = portConfig.sampleRate.value().value;
95 config->base.channelMask = portConfig.channelMask.value();
96 config->base.format = portConfig.format.value();
97}
98
99void setPortConfigFromConfig(AudioPortConfig* portConfig, const AudioConfig& config) {
100 portConfig->sampleRate = Int{ .value = config.base.sampleRate };
101 portConfig->channelMask = config.base.channelMask;
102 portConfig->format = config.base.format;
103}
104
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700105// Note: these converters are for types defined in different AIDL files. Although these
106// AIDL files are copies of each other, however formally these are different types
107// thus we don't use a conversion via a parcelable.
108ConversionResult<media::AudioRoute> ndk2cpp_AudioRoute(const AudioRoute& ndk) {
109 media::AudioRoute cpp;
110 cpp.sourcePortIds.insert(
111 cpp.sourcePortIds.end(), ndk.sourcePortIds.begin(), ndk.sourcePortIds.end());
112 cpp.sinkPortId = ndk.sinkPortId;
113 cpp.isExclusive = ndk.isExclusive;
David Li9cf5e622023-03-21 00:51:10 +0800114 return cpp;
115}
116
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700117template<typename T>
118std::shared_ptr<T> retrieveSubInterface(const std::shared_ptr<IModule>& module,
119 ::ndk::ScopedAStatus (IModule::*getT)(std::shared_ptr<T>*)) {
120 if (module != nullptr) {
121 std::shared_ptr<T> instance;
122 if (auto status = (module.get()->*getT)(&instance); status.isOk()) {
123 return instance;
124 }
125 }
126 return nullptr;
127}
128
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800129} // namespace
130
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700131DeviceHalAidl::DeviceHalAidl(const std::string& instance, const std::shared_ptr<IModule>& module,
132 const std::shared_ptr<IHalAdapterVendorExtension>& vext)
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700133 : ConversionHelperAidl("DeviceHalAidl"),
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700134 mInstance(instance), mModule(module), mVendorExt(vext),
Mikhail Naganovccc82112023-04-27 18:14:15 -0700135 mTelephony(retrieveSubInterface<ITelephony>(module, &IModule::getTelephony)),
136 mBluetooth(retrieveSubInterface<IBluetooth>(module, &IModule::getBluetooth)),
137 mBluetoothA2dp(retrieveSubInterface<IBluetoothA2dp>(module, &IModule::getBluetoothA2dp)),
138 mBluetoothLe(retrieveSubInterface<IBluetoothLe>(module, &IModule::getBluetoothLe)) {
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700139}
140
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700141status_t DeviceHalAidl::getAudioPorts(std::vector<media::audio::common::AudioPort> *ports) {
Mikhail Naganov9e459d72023-05-05 17:36:39 -0700142 return ::aidl::android::convertContainer(mPorts, ports,
143 [](const Ports::value_type& pair) { return ndk2cpp_AudioPort(pair.second); });
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700144}
145
146status_t DeviceHalAidl::getAudioRoutes(std::vector<media::AudioRoute> *routes) {
147 *routes = VALUE_OR_RETURN_STATUS(
148 ::aidl::android::convertContainer<std::vector<media::AudioRoute>>(
149 mRoutes, ndk2cpp_AudioRoute));
150 return OK;
151}
152
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700153status_t DeviceHalAidl::getSupportedModes(std::vector<media::audio::common::AudioMode> *modes) {
154 TIME_CHECK();
155 if (modes == nullptr) {
156 return BAD_VALUE;
157 }
158 if (mModule == nullptr) return NO_INIT;
159 if (mTelephony == nullptr) return INVALID_OPERATION;
160 std::vector<AudioMode> aidlModes;
161 RETURN_STATUS_IF_ERROR(
162 statusTFromBinderStatus(mTelephony->getSupportedAudioModes(&aidlModes)));
163 *modes = VALUE_OR_RETURN_STATUS(
164 ::aidl::android::convertContainer<std::vector<media::audio::common::AudioMode>>(
165 aidlModes, ndk2cpp_AudioMode));
166 return OK;
167}
168
Mikhail Naganov31d46652023-01-10 18:29:25 +0000169status_t DeviceHalAidl::getSupportedDevices(uint32_t*) {
170 // Obsolete.
171 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +0000172}
173
174status_t DeviceHalAidl::initCheck() {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800175 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000176 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800177 std::vector<AudioPort> ports;
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700178 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800179 ALOGW_IF(ports.empty(), "%s: module %s returned an empty list of audio ports",
180 __func__, mInstance.c_str());
181 std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()),
182 [](const auto& p) { return std::make_pair(p.id, p); });
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800183 mDefaultInputPortId = mDefaultOutputPortId = -1;
184 const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
185 for (const auto& pair : mPorts) {
186 const auto& p = pair.second;
187 if (p.ext.getTag() == AudioPortExt::Tag::device &&
188 (p.ext.get<AudioPortExt::Tag::device>().flags & defaultDeviceFlag) != 0) {
189 if (p.flags.getTag() == AudioIoFlags::Tag::input) {
190 mDefaultInputPortId = p.id;
191 } else if (p.flags.getTag() == AudioIoFlags::Tag::output) {
192 mDefaultOutputPortId = p.id;
193 }
194 }
195 }
196 ALOGI("%s: module %s default port ids: input %d, output %d",
197 __func__, mInstance.c_str(), mDefaultInputPortId, mDefaultOutputPortId);
Mikhail Naganov289468a2023-03-29 10:06:15 -0700198 RETURN_STATUS_IF_ERROR(updateRoutes());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800199 std::vector<AudioPortConfig> portConfigs;
200 RETURN_STATUS_IF_ERROR(
201 statusTFromBinderStatus(mModule->getAudioPortConfigs(&portConfigs))); // OK if empty
202 std::transform(portConfigs.begin(), portConfigs.end(),
203 std::inserter(mPortConfigs, mPortConfigs.end()),
204 [](const auto& p) { return std::make_pair(p.id, p); });
jiabin9c07faf2023-04-26 22:00:44 +0000205 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
206 std::inserter(mInitialPortConfigIds, mInitialPortConfigIds.end()),
207 [](const auto& pcPair) { return pcPair.first; });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800208 std::vector<AudioPatch> patches;
209 RETURN_STATUS_IF_ERROR(
210 statusTFromBinderStatus(mModule->getAudioPatches(&patches))); // OK if empty
211 std::transform(patches.begin(), patches.end(),
212 std::inserter(mPatches, mPatches.end()),
213 [](const auto& p) { return std::make_pair(p.id, p); });
Shunkai Yao51202502022-12-12 06:11:46 +0000214 return OK;
215}
216
217status_t DeviceHalAidl::setVoiceVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000218 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000219 if (!mModule) return NO_INIT;
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700220 if (mTelephony == nullptr) return INVALID_OPERATION;
221 ITelephony::TelecomConfig inConfig{ .voiceVolume = Float{volume} }, outConfig;
222 RETURN_STATUS_IF_ERROR(
223 statusTFromBinderStatus(mTelephony->setTelecomConfig(inConfig, &outConfig)));
224 ALOGW_IF(outConfig.voiceVolume.has_value() && volume != outConfig.voiceVolume.value().value,
225 "%s: the resulting voice volume %f is not the same as requested %f",
226 __func__, outConfig.voiceVolume.value().value, volume);
227 return OK;
Shunkai Yao51202502022-12-12 06:11:46 +0000228}
229
230status_t DeviceHalAidl::setMasterVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000231 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000232 if (!mModule) return NO_INIT;
233 return statusTFromBinderStatus(mModule->setMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000234}
235
236status_t DeviceHalAidl::getMasterVolume(float *volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000237 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000238 if (!mModule) return NO_INIT;
239 return statusTFromBinderStatus(mModule->getMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000240}
241
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000242status_t DeviceHalAidl::setMode(audio_mode_t mode) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000243 TIME_CHECK();
244 if (!mModule) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000245 AudioMode audioMode = VALUE_OR_FATAL(::aidl::android::legacy2aidl_audio_mode_t_AudioMode(mode));
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700246 if (mTelephony != nullptr) {
247 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mTelephony->switchAudioMode(audioMode)));
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000248 }
249 return statusTFromBinderStatus(mModule->updateAudioMode(audioMode));
Shunkai Yao51202502022-12-12 06:11:46 +0000250}
251
252status_t DeviceHalAidl::setMicMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000253 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000254 if (!mModule) return NO_INIT;
255 return statusTFromBinderStatus(mModule->setMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000256}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000257
Shunkai Yao51202502022-12-12 06:11:46 +0000258status_t DeviceHalAidl::getMicMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000259 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000260 if (!mModule) return NO_INIT;
261 return statusTFromBinderStatus(mModule->getMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000262}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000263
Shunkai Yao51202502022-12-12 06:11:46 +0000264status_t DeviceHalAidl::setMasterMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000265 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000266 if (!mModule) return NO_INIT;
267 return statusTFromBinderStatus(mModule->setMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000268}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000269
Shunkai Yao51202502022-12-12 06:11:46 +0000270status_t DeviceHalAidl::getMasterMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000271 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000272 if (!mModule) return NO_INIT;
273 return statusTFromBinderStatus(mModule->getMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000274}
275
Mikhail Naganovccc82112023-04-27 18:14:15 -0700276status_t DeviceHalAidl::setParameters(const String8& kvPairs) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000277 if (!mModule) return NO_INIT;
Mikhail Naganovccc82112023-04-27 18:14:15 -0700278 AudioParameter parameters(kvPairs);
279 ALOGD("%s: parameters: \"%s\"", __func__, parameters.toString().c_str());
280
281 if (status_t status = filterAndUpdateBtA2dpParameters(parameters); status != OK) {
282 ALOGW("%s: filtering or updating BT A2DP parameters failed: %d", __func__, status);
283 }
284 if (status_t status = filterAndUpdateBtHfpParameters(parameters); status != OK) {
285 ALOGW("%s: filtering or updating BT HFP parameters failed: %d", __func__, status);
286 }
287 if (status_t status = filterAndUpdateBtLeParameters(parameters); status != OK) {
288 ALOGW("%s: filtering or updating BT LE parameters failed: %d", __func__, status);
289 }
290 if (status_t status = filterAndUpdateBtScoParameters(parameters); status != OK) {
291 ALOGW("%s: filtering or updating BT SCO parameters failed: %d", __func__, status);
292 }
Mikhail Naganove92c34b2023-05-31 14:24:48 -0700293 if (status_t status = filterAndUpdateScreenParameters(parameters); status != OK) {
294 ALOGW("%s: filtering or updating screen parameters failed: %d", __func__, status);
295 }
Mikhail Naganovb9a81312023-07-18 13:55:34 -0700296 if (status_t status = filterAndUpdateTelephonyParameters(parameters); status != OK) {
297 ALOGW("%s: filtering or updating telephony parameters failed: %d", __func__, status);
298 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700299 return parseAndSetVendorParameters(mVendorExt, mModule, parameters);
Shunkai Yao51202502022-12-12 06:11:46 +0000300}
301
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700302status_t DeviceHalAidl::getParameters(const String8& keys, String8 *values) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000303 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000304 if (!mModule) return NO_INIT;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700305 if (values == nullptr) {
306 return BAD_VALUE;
307 }
308 AudioParameter parameterKeys(keys), result;
309 if (status_t status = filterAndRetrieveBtA2dpParameters(parameterKeys, &result); status != OK) {
310 ALOGW("%s: filtering or retrieving BT A2DP parameters failed: %d", __func__, status);
311 }
312 *values = result.toString();
313 return parseAndGetVendorParameters(mVendorExt, mModule, parameterKeys, values);
Shunkai Yao51202502022-12-12 06:11:46 +0000314}
315
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800316namespace {
317
318class Cleanup {
319 public:
320 typedef void (DeviceHalAidl::*Cleaner)(int32_t);
321
322 Cleanup(DeviceHalAidl* device, Cleaner cleaner, int32_t id) :
323 mDevice(device), mCleaner(cleaner), mId(id) {}
324 ~Cleanup() { clean(); }
325 void clean() {
326 if (mDevice != nullptr) (mDevice->*mCleaner)(mId);
327 disarm();
328 }
329 void disarm() { mDevice = nullptr; }
330
331 private:
332 DeviceHalAidl* mDevice;
333 const Cleaner mCleaner;
334 const int32_t mId;
335};
336
337} // namespace
338
339// Since the order of container elements destruction is unspecified,
340// ensure that cleanups are performed from the most recent one and upwards.
341// This is the same as if there were individual Cleanup instances on the stack,
342// however the bonus is that we can disarm all of them with just one statement.
343class DeviceHalAidl::Cleanups : public std::forward_list<Cleanup> {
344 public:
345 ~Cleanups() { for (auto& c : *this) c.clean(); }
346 void disarmAll() { for (auto& c : *this) c.disarm(); }
347};
348
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800349status_t DeviceHalAidl::getInputBufferSize(const struct audio_config* config, size_t* size) {
350 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
351 if (size == nullptr) return BAD_VALUE;
352 TIME_CHECK();
353 if (!mModule) return NO_INIT;
354 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
355 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
356 AudioDevice aidlDevice;
357 aidlDevice.type.type = AudioDeviceType::IN_DEFAULT;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800358 AudioSource aidlSource = AudioSource::DEFAULT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800359 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
360 AudioPortConfig mixPortConfig;
361 Cleanups cleanups;
362 audio_config writableConfig = *config;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700363 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800364 RETURN_STATUS_IF_ERROR(prepareToOpenStream(0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700365 &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800366 *size = aidlConfig.frameCount *
367 getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
368 // Do not disarm cleanups to release temporary port configs.
369 return OK;
370}
371
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800372status_t DeviceHalAidl::prepareToOpenStream(
373 int32_t aidlHandle, const AudioDevice& aidlDevice, const AudioIoFlags& aidlFlags,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800374 AudioSource aidlSource, struct audio_config* config,
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800375 Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700376 AudioPatch* aidlPatch) {
377 ALOGD("%p %s::%s: handle %d, device %s, flags %s, source %s, config %s, mix port config %s",
378 this, getClassName().c_str(), __func__, aidlHandle, aidlDevice.toString().c_str(),
379 aidlFlags.toString().c_str(), toString(aidlSource).c_str(),
380 aidlConfig->toString().c_str(), mixPortConfig->toString().c_str());
jiabin9c07faf2023-04-26 22:00:44 +0000381 resetUnusedPatchesAndPortConfigs();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800382 const bool isInput = aidlFlags.getTag() == AudioIoFlags::Tag::input;
383 // Find / create AudioPortConfigs for the device port and the mix port,
384 // then find / create a patch between them, and open a stream on the mix port.
385 AudioPortConfig devicePortConfig;
386 bool created = false;
jiabin9c07faf2023-04-26 22:00:44 +0000387 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, aidlConfig,
388 &devicePortConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800389 if (created) {
390 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
391 }
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800392 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*aidlConfig, aidlFlags, aidlHandle, aidlSource,
Mikhail Naganov289468a2023-03-29 10:06:15 -0700393 std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800394 if (created) {
395 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
396 }
397 setConfigFromPortConfig(aidlConfig, *mixPortConfig);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800398 if (isInput) {
399 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700400 {devicePortConfig.id}, {mixPortConfig->id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800401 } else {
402 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700403 {mixPortConfig->id}, {devicePortConfig.id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800404 }
405 if (created) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700406 cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, aidlPatch->id);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800407 }
408 if (aidlConfig->frameCount <= 0) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700409 aidlConfig->frameCount = aidlPatch->minimumStreamBufferSizeFrames;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800410 }
411 *config = VALUE_OR_RETURN_STATUS(
412 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(*aidlConfig, isInput));
413 return OK;
414}
415
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800416namespace {
417
418class StreamCallbackBase {
419 protected:
420 explicit StreamCallbackBase(const sp<CallbackBroker>& broker) : mBroker(broker) {}
421 public:
422 void* getCookie() const { return mCookie; }
423 void setCookie(void* cookie) { mCookie = cookie; }
424 sp<CallbackBroker> getBroker() const {
425 if (void* cookie = mCookie; cookie != nullptr) return mBroker.promote();
426 return nullptr;
427 }
428 private:
429 const wp<CallbackBroker> mBroker;
430 std::atomic<void*> mCookie;
431};
432
433template<class C>
434class StreamCallbackBaseHelper {
435 protected:
436 explicit StreamCallbackBaseHelper(const StreamCallbackBase& base) : mBase(base) {}
437 sp<C> getCb(const sp<CallbackBroker>& broker, void* cookie);
438 using CbRef = const sp<C>&;
439 ndk::ScopedAStatus runCb(const std::function<void(CbRef cb)>& f) {
440 if (auto cb = getCb(mBase.getBroker(), mBase.getCookie()); cb != nullptr) f(cb);
441 return ndk::ScopedAStatus::ok();
442 }
443 private:
444 const StreamCallbackBase& mBase;
445};
446
447template<>
448sp<StreamOutHalInterfaceCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>::getCb(
449 const sp<CallbackBroker>& broker, void* cookie) {
450 if (broker != nullptr) return broker->getStreamOutCallback(cookie);
451 return nullptr;
452}
453
454template<>
455sp<StreamOutHalInterfaceEventCallback>
456StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::getCb(
457 const sp<CallbackBroker>& broker, void* cookie) {
458 if (broker != nullptr) return broker->getStreamOutEventCallback(cookie);
459 return nullptr;
460}
461
462template<>
463sp<StreamOutHalInterfaceLatencyModeCallback>
464StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::getCb(
465 const sp<CallbackBroker>& broker, void* cookie) {
466 if (broker != nullptr) return broker->getStreamOutLatencyModeCallback(cookie);
467 return nullptr;
468}
469
470/*
471Note on the callback ownership.
472
473In the Binder ownership model, the server implementation is kept alive
474as long as there is any client (proxy object) alive. This is done by
475incrementing the refcount of the server-side object by the Binder framework.
476When it detects that the last client is gone, it decrements the refcount back.
477
478Thus, it is not needed to keep any references to StreamCallback on our
479side (after we have sent an instance to the client), because we are
480the server-side. The callback object will be kept alive as long as the HAL server
481holds a strong ref to IStreamCallback proxy.
482*/
483
484class OutputStreamCallbackAidl : public StreamCallbackBase,
485 public StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>,
486 public ::aidl::android::hardware::audio::core::BnStreamCallback {
487 public:
488 explicit OutputStreamCallbackAidl(const sp<CallbackBroker>& broker)
489 : StreamCallbackBase(broker),
490 StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>(
491 *static_cast<StreamCallbackBase*>(this)) {}
492 ndk::ScopedAStatus onTransferReady() override {
493 return runCb([](CbRef cb) { cb->onWriteReady(); });
494 }
495 ndk::ScopedAStatus onError() override {
496 return runCb([](CbRef cb) { cb->onError(); });
497 }
498 ndk::ScopedAStatus onDrainReady() override {
499 return runCb([](CbRef cb) { cb->onDrainReady(); });
500 }
501};
502
503class OutputStreamEventCallbackAidl :
504 public StreamCallbackBase,
505 public StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>,
506 public StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>,
507 public ::aidl::android::hardware::audio::core::BnStreamOutEventCallback {
508 public:
509 explicit OutputStreamEventCallbackAidl(const sp<CallbackBroker>& broker)
510 : StreamCallbackBase(broker),
511 StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>(
512 *static_cast<StreamCallbackBase*>(this)),
513 StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>(
514 *static_cast<StreamCallbackBase*>(this)) {}
515 ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& in_audioMetadata) override {
516 std::basic_string<uint8_t> halMetadata(in_audioMetadata.begin(), in_audioMetadata.end());
517 return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb(
518 [&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); });
519 }
520 ndk::ScopedAStatus onRecommendedLatencyModeChanged(
521 const std::vector<AudioLatencyMode>& in_modes) override {
522 auto halModes = VALUE_OR_FATAL(
523 ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
524 in_modes,
525 ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
526 return StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::runCb(
527 [&halModes](auto cb) { cb->onRecommendedLatencyModeChanged(halModes); });
528 }
529};
530
531} // namespace
532
Mikhail Naganov31d46652023-01-10 18:29:25 +0000533status_t DeviceHalAidl::openOutputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800534 audio_io_handle_t handle, audio_devices_t devices,
535 audio_output_flags_t flags, struct audio_config* config,
536 const char* address,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000537 sp<StreamOutHalInterface>* outStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800538 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000539 if (!outStream || !config) {
540 return BAD_VALUE;
541 }
542 TIME_CHECK();
543 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800544 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
545 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
546 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
547 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, false /*isInput*/));
548 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
549 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
550 int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
551 ::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
552 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
553 AudioPortConfig mixPortConfig;
554 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700555 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800556 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
557 AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700558 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800559 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
560 args.portConfigId = mixPortConfig.id;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800561 const bool isOffload = isBitPositionFlagSet(
562 aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD);
563 std::shared_ptr<OutputStreamCallbackAidl> streamCb;
564 if (isOffload) {
565 streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
566 }
567 auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
568 if (isOffload) {
569 args.offloadInfo = aidlConfig.offloadInfo;
570 args.callback = streamCb;
571 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800572 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800573 args.eventCallback = eventCb;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800574 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
575 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800576 StreamContextAidl context(ret.desc, isOffload);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800577 if (!context.isValid()) {
578 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
579 __func__, ret.desc.toString().c_str());
580 return NO_INIT;
581 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700582 *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700583 std::move(ret.stream), mVendorExt, this /*callbackBroker*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700584 mStreams.insert(std::pair(*outStream, aidlPatch.id));
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800585 void* cbCookie = (*outStream).get();
586 {
587 std::lock_guard l(mLock);
588 mCallbacks.emplace(cbCookie, Callbacks{});
589 }
590 if (streamCb) streamCb->setCookie(cbCookie);
591 eventCb->setCookie(cbCookie);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800592 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000593 return OK;
594}
595
Mikhail Naganov31d46652023-01-10 18:29:25 +0000596status_t DeviceHalAidl::openInputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800597 audio_io_handle_t handle, audio_devices_t devices,
598 struct audio_config* config, audio_input_flags_t flags,
599 const char* address, audio_source_t source,
600 audio_devices_t outputDevice, const char* outputDeviceAddress,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000601 sp<StreamInHalInterface>* inStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800602 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000603 if (!inStream || !config) {
604 return BAD_VALUE;
605 }
606 TIME_CHECK();
607 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800608 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
609 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
610 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
611 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
612 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
613 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
614 int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
615 ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
616 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
617 AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
618 ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
619 AudioPortConfig mixPortConfig;
620 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700621 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800622 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700623 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800624 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
625 args.portConfigId = mixPortConfig.id;
626 RecordTrackMetadata aidlTrackMetadata{
627 .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
628 if (outputDevice != AUDIO_DEVICE_NONE) {
629 aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
630 ::aidl::android::legacy2aidl_audio_device_AudioDevice(
631 outputDevice, outputDeviceAddress));
632 }
633 args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
634 args.bufferSizeFrames = aidlConfig.frameCount;
635 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
636 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800637 StreamContextAidl context(ret.desc, false /*isAsynchronous*/);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800638 if (!context.isValid()) {
639 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
640 __func__, ret.desc.toString().c_str());
641 return NO_INIT;
642 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700643 *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700644 std::move(ret.stream), mVendorExt, this /*micInfoProvider*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700645 mStreams.insert(std::pair(*inStream, aidlPatch.id));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800646 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000647 return OK;
648}
649
650status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
651 *supportsPatches = true;
652 return OK;
653}
654
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800655status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
656 const struct audio_port_config* sources,
657 unsigned int num_sinks,
658 const struct audio_port_config* sinks,
659 audio_patch_handle_t* patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800660 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000661 TIME_CHECK();
662 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800663 if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
664 sources == nullptr || sinks == nullptr || patch == nullptr) {
665 return BAD_VALUE;
666 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800667 // When the patch handle (*patch) is AUDIO_PATCH_HANDLE_NONE, it means
668 // the framework wants to create a new patch. The handle has to be generated
669 // by the HAL. Since handles generated this way can only be unique within
670 // a HAL module, the framework generates a globally unique handle, and maps
671 // it on the <HAL module, patch handle> pair.
672 // When the patch handle is set, it meant the framework intends to update
673 // an existing patch.
674 //
675 // This behavior corresponds to HAL module behavior, with the only difference
676 // that the HAL module uses `int32_t` for patch IDs. The following assert ensures
677 // that both the framework and the HAL use the same value for "no ID":
678 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
679 int32_t halPatchId = static_cast<int32_t>(*patch);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800680
681 // Upon conversion, mix port configs contain audio configuration, while
682 // device port configs contain device address. This data is used to find
683 // or create HAL configs.
684 std::vector<AudioPortConfig> aidlSources, aidlSinks;
685 for (unsigned int i = 0; i < num_sources; ++i) {
686 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
687 sources[i].role, sources[i].type)) ==
688 ::aidl::android::AudioPortDirection::INPUT;
689 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
690 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
691 sources[i], isInput, 0)));
692 }
693 for (unsigned int i = 0; i < num_sinks; ++i) {
694 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
695 sinks[i].role, sinks[i].type)) ==
696 ::aidl::android::AudioPortDirection::INPUT;
697 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
698 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
699 sinks[i], isInput, 0)));
700 }
701 Cleanups cleanups;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800702 auto existingPatchIt = halPatchId != 0 ? mPatches.find(halPatchId): mPatches.end();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800703 AudioPatch aidlPatch;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800704 if (existingPatchIt != mPatches.end()) {
705 aidlPatch = existingPatchIt->second;
706 aidlPatch.sourcePortConfigIds.clear();
707 aidlPatch.sinkPortConfigIds.clear();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800708 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800709 ALOGD("%s: sources: %s, sinks: %s",
710 __func__, ::android::internal::ToString(aidlSources).c_str(),
711 ::android::internal::ToString(aidlSinks).c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800712 auto fillPortConfigs = [&](
Mikhail Naganov289468a2023-03-29 10:06:15 -0700713 const std::vector<AudioPortConfig>& configs,
714 const std::set<int32_t>& destinationPortIds,
715 std::vector<int32_t>* ids, std::set<int32_t>* portIds) -> status_t {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800716 for (const auto& s : configs) {
717 AudioPortConfig portConfig;
718 bool created = false;
Mikhail Naganov289468a2023-03-29 10:06:15 -0700719 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
720 s, destinationPortIds, &portConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800721 if (created) {
722 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, portConfig.id);
723 }
724 ids->push_back(portConfig.id);
Mikhail Naganov289468a2023-03-29 10:06:15 -0700725 if (portIds != nullptr) {
726 portIds->insert(portConfig.portId);
727 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800728 }
729 return OK;
730 };
Mikhail Naganov289468a2023-03-29 10:06:15 -0700731 // When looking up port configs, the destinationPortId is only used for mix ports.
732 // Thus, we process device port configs first, and look up the destination port ID from them.
733 bool sourceIsDevice = std::any_of(aidlSources.begin(), aidlSources.end(),
734 [](const auto& config) { return config.ext.getTag() == AudioPortExt::device; });
735 const std::vector<AudioPortConfig>& devicePortConfigs =
736 sourceIsDevice ? aidlSources : aidlSinks;
737 std::vector<int32_t>* devicePortConfigIds =
738 sourceIsDevice ? &aidlPatch.sourcePortConfigIds : &aidlPatch.sinkPortConfigIds;
739 const std::vector<AudioPortConfig>& mixPortConfigs =
740 sourceIsDevice ? aidlSinks : aidlSources;
741 std::vector<int32_t>* mixPortConfigIds =
742 sourceIsDevice ? &aidlPatch.sinkPortConfigIds : &aidlPatch.sourcePortConfigIds;
743 std::set<int32_t> devicePortIds;
744 RETURN_STATUS_IF_ERROR(fillPortConfigs(
745 devicePortConfigs, std::set<int32_t>(), devicePortConfigIds, &devicePortIds));
746 RETURN_STATUS_IF_ERROR(fillPortConfigs(
747 mixPortConfigs, devicePortIds, mixPortConfigIds, nullptr));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800748 if (existingPatchIt != mPatches.end()) {
749 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
750 mModule->setAudioPatch(aidlPatch, &aidlPatch)));
751 existingPatchIt->second = aidlPatch;
752 } else {
753 bool created = false;
754 RETURN_STATUS_IF_ERROR(findOrCreatePatch(aidlPatch, &aidlPatch, &created));
755 // Since no cleanup of the patch is needed, 'created' is ignored.
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800756 halPatchId = aidlPatch.id;
757 *patch = static_cast<audio_patch_handle_t>(halPatchId);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800758 }
759 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000760 return OK;
761}
762
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800763status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800764 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000765 TIME_CHECK();
766 if (!mModule) return NO_INIT;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800767 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
768 if (patch == AUDIO_PATCH_HANDLE_NONE) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800769 return BAD_VALUE;
770 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800771 int32_t halPatchId = static_cast<int32_t>(patch);
772 auto patchIt = mPatches.find(halPatchId);
773 if (patchIt == mPatches.end()) {
774 ALOGE("%s: patch with id %d not found", __func__, halPatchId);
775 return BAD_VALUE;
776 }
777 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->resetAudioPatch(halPatchId)));
778 mPatches.erase(patchIt);
Shunkai Yao51202502022-12-12 06:11:46 +0000779 return OK;
780}
781
Mikhail Naganove93a0862023-03-15 17:06:59 -0700782status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
783 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000784 TIME_CHECK();
785 if (!mModule) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700786 if (port == nullptr) {
787 return BAD_VALUE;
788 }
789 audio_port_v7 portV7;
790 audio_populate_audio_port_v7(port, &portV7);
791 RETURN_STATUS_IF_ERROR(getAudioPort(&portV7));
792 return audio_populate_audio_port(&portV7, port) ? OK : BAD_VALUE;
793}
794
795status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
796 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
797 TIME_CHECK();
798 if (!mModule) return NO_INIT;
799 if (port == nullptr) {
800 return BAD_VALUE;
801 }
802 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
803 ::aidl::android::AudioPortDirection::INPUT;
804 auto aidlPort = VALUE_OR_RETURN_STATUS(
805 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
806 if (aidlPort.ext.getTag() != AudioPortExt::device) {
807 ALOGE("%s: provided port is not a device port (module %s): %s",
808 __func__, mInstance.c_str(), aidlPort.toString().c_str());
809 return BAD_VALUE;
810 }
811 const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
812 // It seems that we don't have to call HAL since all valid ports have been added either
813 // during initialization, or while handling connection of an external device.
814 auto portsIt = findPort(matchDevice);
815 if (portsIt == mPorts.end()) {
816 ALOGE("%s: device port for device %s is not found in the module %s",
817 __func__, matchDevice.toString().c_str(), mInstance.c_str());
818 return BAD_VALUE;
819 }
820 const int32_t fwkId = aidlPort.id;
821 aidlPort = portsIt->second;
822 aidlPort.id = fwkId;
823 *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
824 aidlPort, isInput));
825 return OK;
826}
827
828status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
829 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
830 TIME_CHECK();
831 if (!mModule) return NO_INIT;
832 if (config == nullptr) {
833 return BAD_VALUE;
834 }
835 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
836 config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
837 AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
838 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
839 *config, isInput, 0 /*portId*/));
840 AudioPortConfig portConfig;
841 bool created = false;
Mikhail Naganov289468a2023-03-29 10:06:15 -0700842 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
843 requestedPortConfig, std::set<int32_t>(), &portConfig, &created));
Shunkai Yao51202502022-12-12 06:11:46 +0000844 return OK;
845}
846
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800847MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
848 if (mMicrophones.status == Microphones::Status::UNKNOWN) {
849 TIME_CHECK();
850 std::vector<MicrophoneInfo> aidlInfo;
851 status_t status = statusTFromBinderStatus(mModule->getMicrophones(&aidlInfo));
852 if (status == OK) {
853 mMicrophones.status = Microphones::Status::QUERIED;
854 mMicrophones.info = std::move(aidlInfo);
855 } else if (status == INVALID_OPERATION) {
856 mMicrophones.status = Microphones::Status::NOT_SUPPORTED;
857 } else {
858 ALOGE("%s: Unexpected status from 'IModule.getMicrophones': %d", __func__, status);
859 return {};
860 }
861 }
862 if (mMicrophones.status == Microphones::Status::QUERIED) {
863 return &mMicrophones.info;
864 }
865 return {}; // NOT_SUPPORTED
866}
867
Shunkai Yao51202502022-12-12 06:11:46 +0000868status_t DeviceHalAidl::getMicrophones(
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800869 std::vector<audio_microphone_characteristic_t>* microphones) {
870 if (!microphones) {
871 return BAD_VALUE;
872 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000873 TIME_CHECK();
874 if (!mModule) return NO_INIT;
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800875 auto staticInfo = getMicrophoneInfo();
876 if (!staticInfo) return INVALID_OPERATION;
877 std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
878 emptyDynamicInfo.reserve(staticInfo->size());
879 std::transform(staticInfo->begin(), staticInfo->end(), std::back_inserter(emptyDynamicInfo),
880 [](const auto& info) { return MicrophoneDynamicInfo{ .id = info.id }; });
881 *microphones = VALUE_OR_RETURN_STATUS(
882 ::aidl::android::convertContainers<std::vector<audio_microphone_characteristic_t>>(
883 *staticInfo, emptyDynamicInfo,
884 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t)
885 );
Shunkai Yao51202502022-12-12 06:11:46 +0000886 return OK;
887}
888
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700889status_t DeviceHalAidl::addDeviceEffect(
890 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
891 TIME_CHECK();
892 if (!mModule) return NO_INIT;
Shunkai Yao51202502022-12-12 06:11:46 +0000893 if (!effect) {
894 return BAD_VALUE;
895 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700896 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
897 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
898 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
899 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
900 *device, isInput, 0));
901 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
902 ALOGE("%s: provided port config is not a device port config: %s",
903 __func__, requestedPortConfig.toString().c_str());
904 return BAD_VALUE;
905 }
906 AudioPortConfig devicePortConfig;
907 bool created;
908 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
909 requestedPortConfig, {} /*destinationPortIds*/, &devicePortConfig, &created));
910 Cleanups cleanups;
911 if (created) {
912 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
913 }
914 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
915 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->addDeviceEffect(
916 devicePortConfig.id, aidlEffect->getIEffect())));
917 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000918 return OK;
919}
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700920status_t DeviceHalAidl::removeDeviceEffect(
921 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
922 TIME_CHECK();
923 if (!mModule) return NO_INIT;
Shunkai Yao51202502022-12-12 06:11:46 +0000924 if (!effect) {
925 return BAD_VALUE;
926 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700927 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
928 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
929 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
930 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
931 *device, isInput, 0));
932 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
933 ALOGE("%s: provided port config is not a device port config: %s",
934 __func__, requestedPortConfig.toString().c_str());
935 return BAD_VALUE;
936 }
937 auto existingPortConfigIt = findPortConfig(
938 requestedPortConfig.ext.get<AudioPortExt::Tag::device>().device);
939 if (existingPortConfigIt == mPortConfigs.end()) {
940 ALOGE("%s: could not find a configured device port for the config %s",
941 __func__, requestedPortConfig.toString().c_str());
942 return BAD_VALUE;
943 }
944 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
945 return statusTFromBinderStatus(mModule->removeDeviceEffect(
946 existingPortConfigIt->first, aidlEffect->getIEffect()));
Shunkai Yao51202502022-12-12 06:11:46 +0000947}
948
949status_t DeviceHalAidl::getMmapPolicyInfos(
David Li9cf5e622023-03-21 00:51:10 +0800950 media::audio::common::AudioMMapPolicyType policyType,
951 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000952 TIME_CHECK();
Mikhail Naganov25bc9a22023-04-21 18:48:16 -0700953 AudioMMapPolicyType mmapPolicyType = VALUE_OR_RETURN_STATUS(
954 cpp2ndk_AudioMMapPolicyType(policyType));
David Li9cf5e622023-03-21 00:51:10 +0800955
956 std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
957
958 if (status_t status = statusTFromBinderStatus(
959 mModule->getMmapPolicyInfos(mmapPolicyType, &mmapPolicyInfos)); status != OK) {
960 return status;
961 }
962
963 *policyInfos = VALUE_OR_RETURN_STATUS(
964 convertContainer<std::vector<media::audio::common::AudioMMapPolicyInfo>>(
965 mmapPolicyInfos, ndk2cpp_AudioMMapPolicyInfo));
Shunkai Yao51202502022-12-12 06:11:46 +0000966 return OK;
967}
968
969int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000970 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800971 int32_t mixerBurstCount = 0;
972 if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
973 return mixerBurstCount;
974 }
975 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000976}
977
978int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000979 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800980 int32_t hardwareBurstMinUsec = 0;
981 if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
982 return hardwareBurstMinUsec;
983 }
984 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000985}
986
987error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000988 TIME_CHECK();
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700989 if (!mModule) return NO_INIT;
990 int32_t aidlHwAvSync;
991 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
992 return VALUE_OR_RETURN_STATUS(
993 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +0000994}
995
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000996status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
997 TIME_CHECK();
998 if (!mModule) return NO_INIT;
999 return mModule->dump(fd, Args(args).args(), args.size());
David Li9cf5e622023-03-21 00:51:10 +08001000}
Shunkai Yao51202502022-12-12 06:11:46 +00001001
Mikhail Naganov3ac95c92023-04-12 13:14:30 -07001002int32_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
Mikhail Naganov31d46652023-01-10 18:29:25 +00001003 TIME_CHECK();
Mikhail Naganov3ac95c92023-04-12 13:14:30 -07001004 if (!mModule) return NO_INIT;
1005 if (supports == nullptr) {
1006 return BAD_VALUE;
1007 }
1008 return statusTFromBinderStatus(mModule->supportsVariableLatency(supports));
Shunkai Yao51202502022-12-12 06:11:46 +00001009}
Mikhail Naganov31d46652023-01-10 18:29:25 +00001010
Vlad Popa03bd5bc2023-01-17 16:16:51 +01001011status_t DeviceHalAidl::getSoundDoseInterface(const std::string& module,
1012 ::ndk::SpAIBinder* soundDoseBinder) {
1013 TIME_CHECK();
1014 if (!mModule) return NO_INIT;
1015 if (mSoundDose == nullptr) {
1016 ndk::ScopedAStatus status = mModule->getSoundDose(&mSoundDose);
1017 if (!status.isOk()) {
1018 ALOGE("%s failed to return the sound dose interface for module %s: %s",
1019 __func__,
1020 module.c_str(),
1021 status.getDescription().c_str());
1022 return BAD_VALUE;
1023 }
1024 }
1025 *soundDoseBinder = mSoundDose->asBinder();
1026 ALOGI("%s using audio AIDL HAL sound dose interface", __func__);
1027
1028 return OK;
1029}
jiabin872de702023-04-27 22:04:31 +00001030
1031status_t DeviceHalAidl::prepareToDisconnectExternalDevice(const struct audio_port_v7* port) {
1032 // There is not AIDL API defined for `prepareToDisconnectExternalDevice`.
1033 // Call `setConnectedState` instead.
1034 // TODO(b/279824103): call prepareToDisconnectExternalDevice when it is added.
1035 const status_t status = setConnectedState(port, false /*connected*/);
1036 if (status == NO_ERROR) {
1037 mDeviceDisconnectionNotified.insert(port->id);
1038 }
1039 return status;
1040}
1041
Mikhail Naganove93a0862023-03-15 17:06:59 -07001042status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
1043 TIME_CHECK();
1044 if (!mModule) return NO_INIT;
1045 if (port == nullptr) {
1046 return BAD_VALUE;
1047 }
jiabin872de702023-04-27 22:04:31 +00001048 if (!connected && mDeviceDisconnectionNotified.erase(port->id) > 0) {
1049 // For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
1050 // and then call `setConnectedState`. However, there is no API for
1051 // `prepareToDisconnectExternalDevice` yet. In that case, `setConnectedState` will be
1052 // called when calling `prepareToDisconnectExternalDevice`. Do not call to the HAL if
1053 // previous call is successful. Also remove the cache here to avoid a large cache after
1054 // a long run.
1055 return NO_ERROR;
1056 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001057 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
1058 ::aidl::android::AudioPortDirection::INPUT;
1059 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
1060 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
1061 if (aidlPort.ext.getTag() != AudioPortExt::device) {
1062 ALOGE("%s: provided port is not a device port (module %s): %s",
1063 __func__, mInstance.c_str(), aidlPort.toString().c_str());
1064 return BAD_VALUE;
1065 }
1066 if (connected) {
1067 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1068 // Reset the device address to find the "template" port.
1069 matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
1070 auto portsIt = findPort(matchDevice);
1071 if (portsIt == mPorts.end()) {
1072 ALOGW("%s: device port for device %s is not found in the module %s",
1073 __func__, matchDevice.toString().c_str(), mInstance.c_str());
1074 return BAD_VALUE;
1075 }
1076 // Use the ID of the "template" port, use all the information from the provided port.
1077 aidlPort.id = portsIt->first;
1078 AudioPort connectedPort;
1079 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
1080 aidlPort, &connectedPort)));
1081 const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
1082 LOG_ALWAYS_FATAL_IF(!inserted,
1083 "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
1084 __func__, mInstance.c_str(), connectedPort.toString().c_str(),
1085 it->second.toString().c_str());
1086 } else { // !connected
1087 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1088 auto portsIt = findPort(matchDevice);
1089 if (portsIt == mPorts.end()) {
1090 ALOGW("%s: device port for device %s is not found in the module %s",
1091 __func__, matchDevice.toString().c_str(), mInstance.c_str());
1092 return BAD_VALUE;
1093 }
1094 // Any streams opened on the external device must be closed by this time,
1095 // thus we can clean up patches and port configs that were created for them.
1096 resetUnusedPatchesAndPortConfigs();
1097 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
1098 portsIt->second.id)));
1099 mPorts.erase(portsIt);
1100 }
Mikhail Naganov289468a2023-03-29 10:06:15 -07001101 return updateRoutes();
Mikhail Naganove93a0862023-03-15 17:06:59 -07001102}
1103
1104status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
1105 TIME_CHECK();
1106 if (!mModule) return NO_INIT;
1107 ModuleDebug debug{ .simulateDeviceConnections = enabled };
1108 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
1109 // This is important to log as it affects HAL behavior.
1110 if (status == OK) {
1111 ALOGI("%s: set enabled: %d", __func__, enabled);
1112 } else {
1113 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
1114 }
1115 return status;
1116}
1117
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001118bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
1119 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1120 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1121}
1122
1123bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
1124 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1125 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1126 return p.portId == mDefaultInputPortId;
1127 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1128 return p.portId == mDefaultOutputPortId;
1129 }
1130 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1131}
1132
David Lia8675d42023-03-30 21:08:06 +08001133status_t DeviceHalAidl::createOrUpdatePortConfig(
1134 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool* created) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001135 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001136 AudioPortConfig appliedPortConfig;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001137 bool applied = false;
1138 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001139 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001140 if (!applied) {
1141 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001142 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001143 if (!applied) {
1144 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001145 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001146 return NO_INIT;
1147 }
1148 }
David Lia8675d42023-03-30 21:08:06 +08001149
1150 int32_t id = appliedPortConfig.id;
1151 if (requestedPortConfig.id != 0 && requestedPortConfig.id != id) {
1152 LOG_ALWAYS_FATAL("%s: requested port config id %d changed to %d", __func__,
1153 requestedPortConfig.id, id);
1154 }
1155
1156 auto [it, inserted] = mPortConfigs.insert_or_assign(std::move(id),
1157 std::move(appliedPortConfig));
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001158 *result = it;
David Lia8675d42023-03-30 21:08:06 +08001159 *created = inserted;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001160 return OK;
1161}
1162
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001163status_t DeviceHalAidl::filterAndRetrieveBtA2dpParameters(
1164 AudioParameter &keys, AudioParameter *result) {
1165 TIME_CHECK();
1166 if (String8 key = String8(AudioParameter::keyReconfigA2dpSupported); keys.containsKey(key)) {
1167 keys.remove(key);
1168 bool supports;
1169 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1170 mBluetoothA2dp->supportsOffloadReconfiguration(&supports)));
1171 result->addInt(key, supports ? 1 : 0);
1172 }
1173 return OK;
1174}
1175
Mikhail Naganovccc82112023-04-27 18:14:15 -07001176status_t DeviceHalAidl::filterAndUpdateBtA2dpParameters(AudioParameter &parameters) {
1177 TIME_CHECK();
1178 std::optional<bool> a2dpEnabled;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001179 std::optional<std::vector<VendorParameter>> reconfigureOffload;
Mikhail Naganovccc82112023-04-27 18:14:15 -07001180 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1181 parameters, String8(AudioParameter::keyBtA2dpSuspended),
1182 [&a2dpEnabled](const String8& trueOrFalse) {
1183 if (trueOrFalse == AudioParameter::valueTrue) {
1184 a2dpEnabled = false; // 'suspended' == true
1185 return OK;
1186 } else if (trueOrFalse == AudioParameter::valueFalse) {
1187 a2dpEnabled = true; // 'suspended' == false
1188 return OK;
1189 }
1190 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1191 AudioParameter::keyBtA2dpSuspended, trueOrFalse.c_str());
1192 return BAD_VALUE;
1193 }));
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001194 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1195 parameters, String8(AudioParameter::keyReconfigA2dp),
1196 [&](const String8& value) -> status_t {
1197 if (mVendorExt != nullptr) {
1198 std::vector<VendorParameter> result;
1199 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1200 mVendorExt->parseBluetoothA2dpReconfigureOffload(
1201 std::string(value.c_str()), &result)));
1202 reconfigureOffload = std::move(result);
1203 } else {
1204 reconfigureOffload = std::vector<VendorParameter>();
1205 }
1206 return OK;
1207 }));
Mikhail Naganovccc82112023-04-27 18:14:15 -07001208 if (mBluetoothA2dp != nullptr && a2dpEnabled.has_value()) {
1209 return statusTFromBinderStatus(mBluetoothA2dp->setEnabled(a2dpEnabled.value()));
1210 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001211 if (mBluetoothA2dp != nullptr && reconfigureOffload.has_value()) {
1212 return statusTFromBinderStatus(mBluetoothA2dp->reconfigureOffload(
1213 reconfigureOffload.value()));
1214 }
Mikhail Naganovccc82112023-04-27 18:14:15 -07001215 return OK;
1216}
1217
1218status_t DeviceHalAidl::filterAndUpdateBtHfpParameters(AudioParameter &parameters) {
1219 TIME_CHECK();
1220 IBluetooth::HfpConfig hfpConfig;
1221 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1222 parameters, String8(AudioParameter::keyBtHfpEnable),
1223 [&hfpConfig](const String8& trueOrFalse) {
1224 if (trueOrFalse == AudioParameter::valueTrue) {
1225 hfpConfig.isEnabled = Boolean{ .value = true };
1226 return OK;
1227 } else if (trueOrFalse == AudioParameter::valueFalse) {
1228 hfpConfig.isEnabled = Boolean{ .value = false };
1229 return OK;
1230 }
1231 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1232 AudioParameter::keyBtHfpEnable, trueOrFalse.c_str());
1233 return BAD_VALUE;
1234 }));
1235 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1236 parameters, String8(AudioParameter::keyBtHfpSamplingRate),
1237 [&hfpConfig](int sampleRate) {
1238 return sampleRate > 0 ?
1239 hfpConfig.sampleRate = Int{ .value = sampleRate }, OK : BAD_VALUE;
1240 }));
1241 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1242 parameters, String8(AudioParameter::keyBtHfpVolume),
1243 [&hfpConfig](int volume0to15) {
1244 if (volume0to15 >= 0 && volume0to15 <= 15) {
1245 hfpConfig.volume = Float{ .value = volume0to15 / 15.0f };
1246 return OK;
1247 }
1248 return BAD_VALUE;
1249 }));
1250 if (mBluetooth != nullptr && hfpConfig != IBluetooth::HfpConfig{}) {
1251 IBluetooth::HfpConfig newHfpConfig;
1252 return statusTFromBinderStatus(mBluetooth->setHfpConfig(hfpConfig, &newHfpConfig));
1253 }
1254 return OK;
1255}
1256
1257status_t DeviceHalAidl::filterAndUpdateBtLeParameters(AudioParameter &parameters) {
1258 TIME_CHECK();
1259 std::optional<bool> leEnabled;
1260 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1261 parameters, String8(AudioParameter::keyBtLeSuspended),
1262 [&leEnabled](const String8& trueOrFalse) {
1263 if (trueOrFalse == AudioParameter::valueTrue) {
1264 leEnabled = false; // 'suspended' == true
1265 return OK;
1266 } else if (trueOrFalse == AudioParameter::valueFalse) {
1267 leEnabled = true; // 'suspended' == false
1268 return OK;
1269 }
1270 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1271 AudioParameter::keyBtLeSuspended, trueOrFalse.c_str());
1272 return BAD_VALUE;
1273 }));
1274 if (mBluetoothLe != nullptr && leEnabled.has_value()) {
1275 return statusTFromBinderStatus(mBluetoothLe->setEnabled(leEnabled.value()));
1276 }
1277 return OK;
1278}
1279
1280status_t DeviceHalAidl::filterAndUpdateBtScoParameters(AudioParameter &parameters) {
1281 TIME_CHECK();
1282 IBluetooth::ScoConfig scoConfig;
1283 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1284 parameters, String8(AudioParameter::keyBtSco),
1285 [&scoConfig](const String8& onOrOff) {
1286 if (onOrOff == AudioParameter::valueOn) {
1287 scoConfig.isEnabled = Boolean{ .value = true };
1288 return OK;
1289 } else if (onOrOff == AudioParameter::valueOff) {
1290 scoConfig.isEnabled = Boolean{ .value = false };
1291 return OK;
1292 }
1293 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1294 AudioParameter::keyBtSco, onOrOff.c_str());
1295 return BAD_VALUE;
1296 }));
1297 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1298 parameters, String8(AudioParameter::keyBtScoHeadsetName),
1299 [&scoConfig](const String8& name) {
1300 scoConfig.debugName = name;
1301 return OK;
1302 }));
1303 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1304 parameters, String8(AudioParameter::keyBtNrec),
1305 [&scoConfig](const String8& onOrOff) {
1306 if (onOrOff == AudioParameter::valueOn) {
1307 scoConfig.isNrecEnabled = Boolean{ .value = true };
1308 return OK;
1309 } else if (onOrOff == AudioParameter::valueOff) {
1310 scoConfig.isNrecEnabled = Boolean{ .value = false };
1311 return OK;
1312 }
1313 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1314 AudioParameter::keyBtNrec, onOrOff.c_str());
1315 return BAD_VALUE;
1316 }));
1317 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1318 parameters, String8(AudioParameter::keyBtScoWb),
1319 [&scoConfig](const String8& onOrOff) {
1320 if (onOrOff == AudioParameter::valueOn) {
1321 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO_WB;
1322 return OK;
1323 } else if (onOrOff == AudioParameter::valueOff) {
1324 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO;
1325 return OK;
1326 }
1327 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1328 AudioParameter::keyBtScoWb, onOrOff.c_str());
1329 return BAD_VALUE;
1330 }));
1331 if (mBluetooth != nullptr && scoConfig != IBluetooth::ScoConfig{}) {
1332 IBluetooth::ScoConfig newScoConfig;
1333 return statusTFromBinderStatus(mBluetooth->setScoConfig(scoConfig, &newScoConfig));
1334 }
1335 return OK;
1336}
1337
Mikhail Naganove92c34b2023-05-31 14:24:48 -07001338status_t DeviceHalAidl::filterAndUpdateScreenParameters(AudioParameter &parameters) {
1339 TIME_CHECK();
1340 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1341 parameters, String8(AudioParameter::keyScreenState),
1342 [&](const String8& onOrOff) -> status_t {
1343 std::optional<bool> isTurnedOn;
1344 if (onOrOff == AudioParameter::valueOn) {
1345 isTurnedOn = true;
1346 } else if (onOrOff == AudioParameter::valueOff) {
1347 isTurnedOn = false;
1348 }
1349 if (!isTurnedOn.has_value()) {
1350 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1351 AudioParameter::keyScreenState, onOrOff.c_str());
1352 return BAD_VALUE;
1353 }
1354 return statusTFromBinderStatus(
1355 mModule->updateScreenState(isTurnedOn.value()));
1356 }));
1357 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1358 parameters, String8(AudioParameter::keyScreenRotation),
1359 [&](int rotationDegrees) -> status_t {
1360 IModule::ScreenRotation rotation;
1361 switch (rotationDegrees) {
1362 case 0: rotation = IModule::ScreenRotation::DEG_0; break;
1363 case 90: rotation = IModule::ScreenRotation::DEG_90; break;
1364 case 180: rotation = IModule::ScreenRotation::DEG_180; break;
1365 case 270: rotation = IModule::ScreenRotation::DEG_270; break;
1366 default:
1367 ALOGE("setParameters: parameter key \"%s\" has invalid value %d",
1368 AudioParameter::keyScreenRotation, rotationDegrees);
1369 return BAD_VALUE;
1370 }
1371 return statusTFromBinderStatus(mModule->updateScreenRotation(rotation));
1372 }));
1373 return OK;
1374}
1375
Mikhail Naganovb9a81312023-07-18 13:55:34 -07001376status_t DeviceHalAidl::filterAndUpdateTelephonyParameters(AudioParameter &parameters) {
1377 TIME_CHECK();
1378 using TtyMode = ITelephony::TelecomConfig::TtyMode;
1379 ITelephony::TelecomConfig telConfig;
1380 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1381 parameters, String8(AudioParameter::keyTtyMode),
1382 [&telConfig](const String8& mode) {
1383 if (mode == AudioParameter::valueTtyModeOff) {
1384 telConfig.ttyMode = TtyMode::OFF;
1385 return OK;
1386 } else if (mode == AudioParameter::valueTtyModeFull) {
1387 telConfig.ttyMode = TtyMode::FULL;
1388 return OK;
1389 } else if (mode == AudioParameter::valueTtyModeHco) {
1390 telConfig.ttyMode = TtyMode::HCO;
1391 return OK;
1392 } else if (mode == AudioParameter::valueTtyModeVco) {
1393 telConfig.ttyMode = TtyMode::VCO;
1394 return OK;
1395 }
1396 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1397 AudioParameter::keyTtyMode, mode.c_str());
1398 return BAD_VALUE;
1399 }));
1400 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1401 parameters, String8(AudioParameter::keyHacSetting),
1402 [&telConfig](const String8& onOrOff) {
1403 if (onOrOff == AudioParameter::valueHacOn) {
1404 telConfig.isHacEnabled = Boolean{ .value = true };
1405 return OK;
1406 } else if (onOrOff == AudioParameter::valueHacOff) {
1407 telConfig.isHacEnabled = Boolean{ .value = false };
1408 return OK;
1409 }
1410 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1411 AudioParameter::keyHacSetting, onOrOff.c_str());
1412 return BAD_VALUE;
1413 }));
1414 if (mTelephony != nullptr && telConfig != ITelephony::TelecomConfig{}) {
1415 ITelephony::TelecomConfig newTelConfig;
1416 return statusTFromBinderStatus(
1417 mTelephony->setTelecomConfig(telConfig, &newTelConfig));
1418 }
1419 return OK;
1420}
1421
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001422status_t DeviceHalAidl::findOrCreatePatch(
1423 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
1424 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
1425 requestedPatch.sourcePortConfigIds.end());
1426 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
1427 requestedPatch.sinkPortConfigIds.end());
1428 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
1429}
1430
1431status_t DeviceHalAidl::findOrCreatePatch(
1432 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
1433 AudioPatch* patch, bool* created) {
1434 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
1435 if (patchIt == mPatches.end()) {
1436 TIME_CHECK();
1437 AudioPatch requestedPatch, appliedPatch;
1438 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
1439 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
1440 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
1441 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
1442 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
1443 requestedPatch, &appliedPatch)));
1444 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
1445 *created = true;
1446 } else {
1447 *created = false;
1448 }
1449 *patch = patchIt->second;
1450 return OK;
1451}
1452
jiabin9c07faf2023-04-26 22:00:44 +00001453status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device, const AudioConfig* config,
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001454 AudioPortConfig* portConfig, bool* created) {
1455 auto portConfigIt = findPortConfig(device);
1456 if (portConfigIt == mPortConfigs.end()) {
1457 auto portsIt = findPort(device);
1458 if (portsIt == mPorts.end()) {
1459 ALOGE("%s: device port for device %s is not found in the module %s",
1460 __func__, device.toString().c_str(), mInstance.c_str());
1461 return BAD_VALUE;
1462 }
1463 AudioPortConfig requestedPortConfig;
1464 requestedPortConfig.portId = portsIt->first;
jiabin9c07faf2023-04-26 22:00:44 +00001465 if (config != nullptr) {
1466 setPortConfigFromConfig(&requestedPortConfig, *config);
1467 }
David Lia8675d42023-03-30 21:08:06 +08001468 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1469 created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001470 } else {
1471 *created = false;
1472 }
1473 *portConfig = portConfigIt->second;
1474 return OK;
1475}
1476
1477status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001478 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001479 AudioSource source, const std::set<int32_t>& destinationPortIds,
1480 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001481 // These flags get removed one by one in this order when retrying port finding.
1482 static const std::vector<AudioInputFlags> kOptionalInputFlags{
1483 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001484 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001485 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001486 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
1487 AudioIoFlags matchFlags = flags.value();
Mikhail Naganov289468a2023-03-29 10:06:15 -07001488 auto portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001489 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
1490 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
1491 if (!isBitPositionFlagSet(
1492 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
1493 ++optionalInputFlagsIt;
1494 continue;
1495 }
1496 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
1497 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
Mikhail Naganov289468a2023-03-29 10:06:15 -07001498 portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001499 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
1500 "retried with flags %s", __func__, config.toString().c_str(),
1501 flags.value().toString().c_str(), mInstance.c_str(),
1502 matchFlags.toString().c_str());
1503 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001504 if (portsIt == mPorts.end()) {
1505 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001506 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001507 mInstance.c_str());
1508 return BAD_VALUE;
1509 }
1510 AudioPortConfig requestedPortConfig;
1511 requestedPortConfig.portId = portsIt->first;
1512 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001513 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001514 if (matchFlags.getTag() == AudioIoFlags::Tag::input
1515 && source != AudioSource::SYS_RESERVED_INVALID) {
1516 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
1517 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
1518 }
David Lia8675d42023-03-30 21:08:06 +08001519 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1520 created));
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001521 } else if (!flags.has_value()) {
1522 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
1523 "and was not created as flags are not specified",
1524 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
1525 return BAD_VALUE;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001526 } else {
David Lia8675d42023-03-30 21:08:06 +08001527 AudioPortConfig requestedPortConfig = portConfigIt->second;
1528 if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
1529 AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
1530 if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
1531 source != AudioSource::SYS_RESERVED_INVALID) {
1532 mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
1533 }
1534 }
1535
1536 if (requestedPortConfig != portConfigIt->second) {
1537 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1538 created));
1539 } else {
1540 *created = false;
1541 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001542 }
1543 *portConfig = portConfigIt->second;
1544 return OK;
1545}
1546
1547status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001548 const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
1549 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001550 using Tag = AudioPortExt::Tag;
1551 if (requestedPortConfig.ext.getTag() == Tag::mix) {
1552 if (const auto& p = requestedPortConfig;
1553 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001554 !p.format.has_value()) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001555 ALOGW("%s: provided mix port config is not fully specified: %s",
1556 __func__, p.toString().c_str());
1557 return BAD_VALUE;
1558 }
1559 AudioConfig config;
1560 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001561 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
1562 AudioPortMixExtUseCase::Tag::source ?
1563 requestedPortConfig.ext.get<Tag::mix>().usecase.
1564 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001565 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001566 requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
1567 portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001568 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
1569 return findOrCreatePortConfig(
jiabin9c07faf2023-04-26 22:00:44 +00001570 requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
1571 portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001572 }
1573 ALOGW("%s: unsupported audio port config: %s",
1574 __func__, requestedPortConfig.toString().c_str());
1575 return BAD_VALUE;
1576}
1577
1578DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
1579 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
1580 return std::find_if(mPatches.begin(), mPatches.end(),
1581 [&](const auto& pair) {
1582 const auto& p = pair.second;
1583 std::set<int32_t> patchSrcs(
1584 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
1585 std::set<int32_t> patchSinks(
1586 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
1587 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
1588}
1589
1590DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001591 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1592 return mPorts.find(mDefaultInputPortId);
1593 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1594 return mPorts.find(mDefaultOutputPortId);
1595 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001596 return std::find_if(mPorts.begin(), mPorts.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001597 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001598}
1599
1600DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001601 const AudioConfig& config, const AudioIoFlags& flags,
1602 const std::set<int32_t>& destinationPortIds) {
Mikhail Naganove93a0862023-03-15 17:06:59 -07001603 auto belongsToProfile = [&config](const AudioProfile& prof) {
1604 return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
1605 (config.base.channelMask.getTag() == AudioChannelLayout::none ||
1606 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
1607 config.base.channelMask) != prof.channelMasks.end()) &&
1608 (config.base.sampleRate == 0 ||
1609 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
1610 config.base.sampleRate) != prof.sampleRates.end());
1611 };
jiabin9c07faf2023-04-26 22:00:44 +00001612 static const std::vector<AudioOutputFlags> kOptionalOutputFlags{AudioOutputFlags::BIT_PERFECT};
1613 int optionalFlags = 0;
1614 auto flagMatches = [&flags, &optionalFlags](const AudioIoFlags& portFlags) {
1615 // Ports should be able to match if the optional flags are not requested.
1616 return portFlags == flags ||
1617 (portFlags.getTag() == AudioIoFlags::Tag::output &&
1618 AudioIoFlags::make<AudioIoFlags::Tag::output>(
1619 portFlags.get<AudioIoFlags::Tag::output>() &
1620 ~optionalFlags) == flags);
1621 };
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001622 auto matcher = [&](const auto& pair) {
1623 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001624 return p.ext.getTag() == AudioPortExt::Tag::mix &&
jiabin9c07faf2023-04-26 22:00:44 +00001625 flagMatches(p.flags) &&
Mikhail Naganov289468a2023-03-29 10:06:15 -07001626 (destinationPortIds.empty() ||
1627 std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
1628 [&](const int32_t destId) { return mRoutingMatrix.count(
1629 std::make_pair(p.id, destId)) != 0; })) &&
Mikhail Naganove93a0862023-03-15 17:06:59 -07001630 (p.profiles.empty() ||
1631 std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
1632 p.profiles.end()); };
jiabin9c07faf2023-04-26 22:00:44 +00001633 auto result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1634 if (result == mPorts.end() && flags.getTag() == AudioIoFlags::Tag::output) {
1635 auto optionalOutputFlagsIt = kOptionalOutputFlags.begin();
1636 while (result == mPorts.end() && optionalOutputFlagsIt != kOptionalOutputFlags.end()) {
1637 if (isBitPositionFlagSet(
1638 flags.get<AudioIoFlags::Tag::output>(), *optionalOutputFlagsIt)) {
1639 // If the flag is set by the request, it must be matched.
1640 ++optionalOutputFlagsIt;
1641 continue;
1642 }
1643 optionalFlags |= makeBitPositionFlagMask(*optionalOutputFlagsIt++);
1644 result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1645 ALOGI("%s: port for config %s, flags %s was not found in the module %s, "
1646 "retried with excluding optional flags %#x", __func__, config.toString().c_str(),
1647 flags.toString().c_str(), mInstance.c_str(), optionalFlags);
1648 }
1649 }
1650 return result;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001651}
1652
1653DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001654 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001655 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001656}
1657
1658DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001659 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001660 using Tag = AudioPortExt::Tag;
1661 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
1662 [&](const auto& pair) {
1663 const auto& p = pair.second;
1664 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
1665 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
1666 !p.format.has_value() || !p.flags.has_value(),
1667 "%s: stored mix port config is not fully specified: %s",
1668 __func__, p.toString().c_str());
1669 return p.ext.getTag() == Tag::mix &&
1670 isConfigEqualToPortConfig(config, p) &&
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001671 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001672 p.ext.template get<Tag::mix>().handle == ioHandle; });
1673}
Mikhail Naganove93a0862023-03-15 17:06:59 -07001674
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001675void DeviceHalAidl::resetPatch(int32_t patchId) {
1676 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1677 mPatches.erase(it);
1678 TIME_CHECK();
1679 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1680 ALOGE("%s: error while resetting patch %d: %s",
1681 __func__, patchId, status.getDescription().c_str());
1682 }
1683 return;
1684 }
1685 ALOGE("%s: patch id %d not found", __func__, patchId);
1686}
1687
1688void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1689 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1690 mPortConfigs.erase(it);
1691 TIME_CHECK();
1692 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1693 !status.isOk()) {
1694 ALOGE("%s: error while resetting port config %d: %s",
1695 __func__, portConfigId, status.getDescription().c_str());
1696 }
1697 return;
1698 }
1699 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1700}
1701
Mikhail Naganove93a0862023-03-15 17:06:59 -07001702void DeviceHalAidl::resetUnusedPatches() {
1703 // Since patches can be created independently of streams via 'createAudioPatch',
1704 // here we only clean up patches for released streams.
1705 for (auto it = mStreams.begin(); it != mStreams.end(); ) {
1706 if (auto streamSp = it->first.promote(); streamSp) {
1707 ++it;
1708 } else {
1709 resetPatch(it->second);
1710 it = mStreams.erase(it);
1711 }
1712 }
1713}
1714
1715void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
1716 resetUnusedPatches();
1717 resetUnusedPortConfigs();
1718}
1719
1720void DeviceHalAidl::resetUnusedPortConfigs() {
1721 // The assumption is that port configs are used to create patches
1722 // (or to open streams, but that involves creation of patches, too). Thus,
1723 // orphaned port configs can and should be reset.
1724 std::set<int32_t> portConfigIds;
1725 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
1726 std::inserter(portConfigIds, portConfigIds.end()),
1727 [](const auto& pcPair) { return pcPair.first; });
1728 for (const auto& p : mPatches) {
1729 for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
1730 for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
1731 }
jiabin9c07faf2023-04-26 22:00:44 +00001732 for (int32_t id : mInitialPortConfigIds) {
1733 portConfigIds.erase(id);
1734 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001735 for (int32_t id : portConfigIds) resetPortConfig(id);
1736}
1737
Mikhail Naganov289468a2023-03-29 10:06:15 -07001738status_t DeviceHalAidl::updateRoutes() {
1739 TIME_CHECK();
Mikhail Naganov289468a2023-03-29 10:06:15 -07001740 RETURN_STATUS_IF_ERROR(
Mikhail Naganovf83b9742023-04-24 13:06:04 -07001741 statusTFromBinderStatus(mModule->getAudioRoutes(&mRoutes)));
1742 ALOGW_IF(mRoutes.empty(), "%s: module %s returned an empty list of audio routes",
Mikhail Naganov289468a2023-03-29 10:06:15 -07001743 __func__, mInstance.c_str());
1744 mRoutingMatrix.clear();
Mikhail Naganovf83b9742023-04-24 13:06:04 -07001745 for (const auto& r : mRoutes) {
Mikhail Naganov289468a2023-03-29 10:06:15 -07001746 for (auto portId : r.sourcePortIds) {
1747 mRoutingMatrix.emplace(r.sinkPortId, portId);
1748 mRoutingMatrix.emplace(portId, r.sinkPortId);
1749 }
1750 }
1751 return OK;
1752}
1753
Mikhail Naganovdfd594e2023-02-08 16:59:41 -08001754void DeviceHalAidl::clearCallbacks(void* cookie) {
1755 std::lock_guard l(mLock);
1756 mCallbacks.erase(cookie);
1757}
1758
1759sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1760 return getCallbackImpl(cookie, &Callbacks::out);
1761}
1762
1763void DeviceHalAidl::setStreamOutCallback(
1764 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1765 setCallbackImpl(cookie, &Callbacks::out, cb);
1766}
1767
1768sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1769 void* cookie) {
1770 return getCallbackImpl(cookie, &Callbacks::event);
1771}
1772
1773void DeviceHalAidl::setStreamOutEventCallback(
1774 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1775 setCallbackImpl(cookie, &Callbacks::event, cb);
1776}
1777
1778sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1779 void* cookie) {
1780 return getCallbackImpl(cookie, &Callbacks::latency);
1781}
1782
1783void DeviceHalAidl::setStreamOutLatencyModeCallback(
1784 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1785 setCallbackImpl(cookie, &Callbacks::latency, cb);
1786}
1787
1788template<class C>
1789sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1790 std::lock_guard l(mLock);
1791 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1792 return ((it->second).*field).promote();
1793 }
1794 return nullptr;
1795}
1796template<class C>
1797void DeviceHalAidl::setCallbackImpl(
1798 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1799 std::lock_guard l(mLock);
1800 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1801 (it->second).*field = cb;
1802 }
1803}
1804
Mikhail Naganov31d46652023-01-10 18:29:25 +00001805} // namespace android