blob: e55ad1441757d587f136cc88eacd312f6d990fbf [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 Naganove7a26ad2023-05-25 17:36:48 -0700296 return parseAndSetVendorParameters(mVendorExt, mModule, parameters);
Shunkai Yao51202502022-12-12 06:11:46 +0000297}
298
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700299status_t DeviceHalAidl::getParameters(const String8& keys, String8 *values) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000300 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000301 if (!mModule) return NO_INIT;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700302 if (values == nullptr) {
303 return BAD_VALUE;
304 }
305 AudioParameter parameterKeys(keys), result;
306 if (status_t status = filterAndRetrieveBtA2dpParameters(parameterKeys, &result); status != OK) {
307 ALOGW("%s: filtering or retrieving BT A2DP parameters failed: %d", __func__, status);
308 }
309 *values = result.toString();
310 return parseAndGetVendorParameters(mVendorExt, mModule, parameterKeys, values);
Shunkai Yao51202502022-12-12 06:11:46 +0000311}
312
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800313namespace {
314
315class Cleanup {
316 public:
317 typedef void (DeviceHalAidl::*Cleaner)(int32_t);
318
319 Cleanup(DeviceHalAidl* device, Cleaner cleaner, int32_t id) :
320 mDevice(device), mCleaner(cleaner), mId(id) {}
321 ~Cleanup() { clean(); }
322 void clean() {
323 if (mDevice != nullptr) (mDevice->*mCleaner)(mId);
324 disarm();
325 }
326 void disarm() { mDevice = nullptr; }
327
328 private:
329 DeviceHalAidl* mDevice;
330 const Cleaner mCleaner;
331 const int32_t mId;
332};
333
334} // namespace
335
336// Since the order of container elements destruction is unspecified,
337// ensure that cleanups are performed from the most recent one and upwards.
338// This is the same as if there were individual Cleanup instances on the stack,
339// however the bonus is that we can disarm all of them with just one statement.
340class DeviceHalAidl::Cleanups : public std::forward_list<Cleanup> {
341 public:
342 ~Cleanups() { for (auto& c : *this) c.clean(); }
343 void disarmAll() { for (auto& c : *this) c.disarm(); }
344};
345
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800346status_t DeviceHalAidl::getInputBufferSize(const struct audio_config* config, size_t* size) {
347 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
348 if (size == nullptr) return BAD_VALUE;
349 TIME_CHECK();
350 if (!mModule) return NO_INIT;
351 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
352 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
353 AudioDevice aidlDevice;
354 aidlDevice.type.type = AudioDeviceType::IN_DEFAULT;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800355 AudioSource aidlSource = AudioSource::DEFAULT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800356 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
357 AudioPortConfig mixPortConfig;
358 Cleanups cleanups;
359 audio_config writableConfig = *config;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700360 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800361 RETURN_STATUS_IF_ERROR(prepareToOpenStream(0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700362 &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800363 *size = aidlConfig.frameCount *
364 getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
365 // Do not disarm cleanups to release temporary port configs.
366 return OK;
367}
368
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800369status_t DeviceHalAidl::prepareToOpenStream(
370 int32_t aidlHandle, const AudioDevice& aidlDevice, const AudioIoFlags& aidlFlags,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800371 AudioSource aidlSource, struct audio_config* config,
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800372 Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700373 AudioPatch* aidlPatch) {
374 ALOGD("%p %s::%s: handle %d, device %s, flags %s, source %s, config %s, mix port config %s",
375 this, getClassName().c_str(), __func__, aidlHandle, aidlDevice.toString().c_str(),
376 aidlFlags.toString().c_str(), toString(aidlSource).c_str(),
377 aidlConfig->toString().c_str(), mixPortConfig->toString().c_str());
jiabin9c07faf2023-04-26 22:00:44 +0000378 resetUnusedPatchesAndPortConfigs();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800379 const bool isInput = aidlFlags.getTag() == AudioIoFlags::Tag::input;
380 // Find / create AudioPortConfigs for the device port and the mix port,
381 // then find / create a patch between them, and open a stream on the mix port.
382 AudioPortConfig devicePortConfig;
383 bool created = false;
jiabin9c07faf2023-04-26 22:00:44 +0000384 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, aidlConfig,
385 &devicePortConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800386 if (created) {
387 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
388 }
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800389 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*aidlConfig, aidlFlags, aidlHandle, aidlSource,
Mikhail Naganov289468a2023-03-29 10:06:15 -0700390 std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800391 if (created) {
392 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
393 }
394 setConfigFromPortConfig(aidlConfig, *mixPortConfig);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800395 if (isInput) {
396 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700397 {devicePortConfig.id}, {mixPortConfig->id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800398 } else {
399 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700400 {mixPortConfig->id}, {devicePortConfig.id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800401 }
402 if (created) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700403 cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, aidlPatch->id);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800404 }
405 if (aidlConfig->frameCount <= 0) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700406 aidlConfig->frameCount = aidlPatch->minimumStreamBufferSizeFrames;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800407 }
408 *config = VALUE_OR_RETURN_STATUS(
409 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(*aidlConfig, isInput));
410 return OK;
411}
412
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800413namespace {
414
415class StreamCallbackBase {
416 protected:
417 explicit StreamCallbackBase(const sp<CallbackBroker>& broker) : mBroker(broker) {}
418 public:
419 void* getCookie() const { return mCookie; }
420 void setCookie(void* cookie) { mCookie = cookie; }
421 sp<CallbackBroker> getBroker() const {
422 if (void* cookie = mCookie; cookie != nullptr) return mBroker.promote();
423 return nullptr;
424 }
425 private:
426 const wp<CallbackBroker> mBroker;
427 std::atomic<void*> mCookie;
428};
429
430template<class C>
431class StreamCallbackBaseHelper {
432 protected:
433 explicit StreamCallbackBaseHelper(const StreamCallbackBase& base) : mBase(base) {}
434 sp<C> getCb(const sp<CallbackBroker>& broker, void* cookie);
435 using CbRef = const sp<C>&;
436 ndk::ScopedAStatus runCb(const std::function<void(CbRef cb)>& f) {
437 if (auto cb = getCb(mBase.getBroker(), mBase.getCookie()); cb != nullptr) f(cb);
438 return ndk::ScopedAStatus::ok();
439 }
440 private:
441 const StreamCallbackBase& mBase;
442};
443
444template<>
445sp<StreamOutHalInterfaceCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>::getCb(
446 const sp<CallbackBroker>& broker, void* cookie) {
447 if (broker != nullptr) return broker->getStreamOutCallback(cookie);
448 return nullptr;
449}
450
451template<>
452sp<StreamOutHalInterfaceEventCallback>
453StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::getCb(
454 const sp<CallbackBroker>& broker, void* cookie) {
455 if (broker != nullptr) return broker->getStreamOutEventCallback(cookie);
456 return nullptr;
457}
458
459template<>
460sp<StreamOutHalInterfaceLatencyModeCallback>
461StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::getCb(
462 const sp<CallbackBroker>& broker, void* cookie) {
463 if (broker != nullptr) return broker->getStreamOutLatencyModeCallback(cookie);
464 return nullptr;
465}
466
467/*
468Note on the callback ownership.
469
470In the Binder ownership model, the server implementation is kept alive
471as long as there is any client (proxy object) alive. This is done by
472incrementing the refcount of the server-side object by the Binder framework.
473When it detects that the last client is gone, it decrements the refcount back.
474
475Thus, it is not needed to keep any references to StreamCallback on our
476side (after we have sent an instance to the client), because we are
477the server-side. The callback object will be kept alive as long as the HAL server
478holds a strong ref to IStreamCallback proxy.
479*/
480
481class OutputStreamCallbackAidl : public StreamCallbackBase,
482 public StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>,
483 public ::aidl::android::hardware::audio::core::BnStreamCallback {
484 public:
485 explicit OutputStreamCallbackAidl(const sp<CallbackBroker>& broker)
486 : StreamCallbackBase(broker),
487 StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>(
488 *static_cast<StreamCallbackBase*>(this)) {}
489 ndk::ScopedAStatus onTransferReady() override {
490 return runCb([](CbRef cb) { cb->onWriteReady(); });
491 }
492 ndk::ScopedAStatus onError() override {
493 return runCb([](CbRef cb) { cb->onError(); });
494 }
495 ndk::ScopedAStatus onDrainReady() override {
496 return runCb([](CbRef cb) { cb->onDrainReady(); });
497 }
498};
499
500class OutputStreamEventCallbackAidl :
501 public StreamCallbackBase,
502 public StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>,
503 public StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>,
504 public ::aidl::android::hardware::audio::core::BnStreamOutEventCallback {
505 public:
506 explicit OutputStreamEventCallbackAidl(const sp<CallbackBroker>& broker)
507 : StreamCallbackBase(broker),
508 StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>(
509 *static_cast<StreamCallbackBase*>(this)),
510 StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>(
511 *static_cast<StreamCallbackBase*>(this)) {}
512 ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& in_audioMetadata) override {
513 std::basic_string<uint8_t> halMetadata(in_audioMetadata.begin(), in_audioMetadata.end());
514 return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb(
515 [&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); });
516 }
517 ndk::ScopedAStatus onRecommendedLatencyModeChanged(
518 const std::vector<AudioLatencyMode>& in_modes) override {
519 auto halModes = VALUE_OR_FATAL(
520 ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
521 in_modes,
522 ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
523 return StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::runCb(
524 [&halModes](auto cb) { cb->onRecommendedLatencyModeChanged(halModes); });
525 }
526};
527
528} // namespace
529
Mikhail Naganov31d46652023-01-10 18:29:25 +0000530status_t DeviceHalAidl::openOutputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800531 audio_io_handle_t handle, audio_devices_t devices,
532 audio_output_flags_t flags, struct audio_config* config,
533 const char* address,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000534 sp<StreamOutHalInterface>* outStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800535 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000536 if (!outStream || !config) {
537 return BAD_VALUE;
538 }
539 TIME_CHECK();
540 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800541 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
542 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
543 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
544 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, false /*isInput*/));
545 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
546 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
547 int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
548 ::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
549 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
550 AudioPortConfig mixPortConfig;
551 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700552 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800553 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
554 AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700555 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800556 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
557 args.portConfigId = mixPortConfig.id;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800558 const bool isOffload = isBitPositionFlagSet(
559 aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD);
560 std::shared_ptr<OutputStreamCallbackAidl> streamCb;
561 if (isOffload) {
562 streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
563 }
564 auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
565 if (isOffload) {
566 args.offloadInfo = aidlConfig.offloadInfo;
567 args.callback = streamCb;
568 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800569 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800570 args.eventCallback = eventCb;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800571 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
572 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800573 StreamContextAidl context(ret.desc, isOffload);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800574 if (!context.isValid()) {
575 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
576 __func__, ret.desc.toString().c_str());
577 return NO_INIT;
578 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700579 *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700580 std::move(ret.stream), mVendorExt, this /*callbackBroker*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700581 mStreams.insert(std::pair(*outStream, aidlPatch.id));
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800582 void* cbCookie = (*outStream).get();
583 {
584 std::lock_guard l(mLock);
585 mCallbacks.emplace(cbCookie, Callbacks{});
586 }
587 if (streamCb) streamCb->setCookie(cbCookie);
588 eventCb->setCookie(cbCookie);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800589 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000590 return OK;
591}
592
Mikhail Naganov31d46652023-01-10 18:29:25 +0000593status_t DeviceHalAidl::openInputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800594 audio_io_handle_t handle, audio_devices_t devices,
595 struct audio_config* config, audio_input_flags_t flags,
596 const char* address, audio_source_t source,
597 audio_devices_t outputDevice, const char* outputDeviceAddress,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000598 sp<StreamInHalInterface>* inStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800599 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000600 if (!inStream || !config) {
601 return BAD_VALUE;
602 }
603 TIME_CHECK();
604 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800605 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
606 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
607 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
608 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
609 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
610 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
611 int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
612 ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
613 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
614 AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
615 ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
616 AudioPortConfig mixPortConfig;
617 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700618 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800619 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700620 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800621 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
622 args.portConfigId = mixPortConfig.id;
623 RecordTrackMetadata aidlTrackMetadata{
624 .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
625 if (outputDevice != AUDIO_DEVICE_NONE) {
626 aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
627 ::aidl::android::legacy2aidl_audio_device_AudioDevice(
628 outputDevice, outputDeviceAddress));
629 }
630 args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
631 args.bufferSizeFrames = aidlConfig.frameCount;
632 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
633 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800634 StreamContextAidl context(ret.desc, false /*isAsynchronous*/);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800635 if (!context.isValid()) {
636 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
637 __func__, ret.desc.toString().c_str());
638 return NO_INIT;
639 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700640 *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700641 std::move(ret.stream), mVendorExt, this /*micInfoProvider*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700642 mStreams.insert(std::pair(*inStream, aidlPatch.id));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800643 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000644 return OK;
645}
646
647status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
648 *supportsPatches = true;
649 return OK;
650}
651
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800652status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
653 const struct audio_port_config* sources,
654 unsigned int num_sinks,
655 const struct audio_port_config* sinks,
656 audio_patch_handle_t* patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800657 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000658 TIME_CHECK();
659 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800660 if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
661 sources == nullptr || sinks == nullptr || patch == nullptr) {
662 return BAD_VALUE;
663 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800664 // When the patch handle (*patch) is AUDIO_PATCH_HANDLE_NONE, it means
665 // the framework wants to create a new patch. The handle has to be generated
666 // by the HAL. Since handles generated this way can only be unique within
667 // a HAL module, the framework generates a globally unique handle, and maps
668 // it on the <HAL module, patch handle> pair.
669 // When the patch handle is set, it meant the framework intends to update
670 // an existing patch.
671 //
672 // This behavior corresponds to HAL module behavior, with the only difference
673 // that the HAL module uses `int32_t` for patch IDs. The following assert ensures
674 // that both the framework and the HAL use the same value for "no ID":
675 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
676 int32_t halPatchId = static_cast<int32_t>(*patch);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800677
678 // Upon conversion, mix port configs contain audio configuration, while
679 // device port configs contain device address. This data is used to find
680 // or create HAL configs.
681 std::vector<AudioPortConfig> aidlSources, aidlSinks;
682 for (unsigned int i = 0; i < num_sources; ++i) {
683 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
684 sources[i].role, sources[i].type)) ==
685 ::aidl::android::AudioPortDirection::INPUT;
686 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
687 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
688 sources[i], isInput, 0)));
689 }
690 for (unsigned int i = 0; i < num_sinks; ++i) {
691 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
692 sinks[i].role, sinks[i].type)) ==
693 ::aidl::android::AudioPortDirection::INPUT;
694 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
695 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
696 sinks[i], isInput, 0)));
697 }
698 Cleanups cleanups;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800699 auto existingPatchIt = halPatchId != 0 ? mPatches.find(halPatchId): mPatches.end();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800700 AudioPatch aidlPatch;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800701 if (existingPatchIt != mPatches.end()) {
702 aidlPatch = existingPatchIt->second;
703 aidlPatch.sourcePortConfigIds.clear();
704 aidlPatch.sinkPortConfigIds.clear();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800705 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800706 ALOGD("%s: sources: %s, sinks: %s",
707 __func__, ::android::internal::ToString(aidlSources).c_str(),
708 ::android::internal::ToString(aidlSinks).c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800709 auto fillPortConfigs = [&](
Mikhail Naganov289468a2023-03-29 10:06:15 -0700710 const std::vector<AudioPortConfig>& configs,
711 const std::set<int32_t>& destinationPortIds,
712 std::vector<int32_t>* ids, std::set<int32_t>* portIds) -> status_t {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800713 for (const auto& s : configs) {
714 AudioPortConfig portConfig;
715 bool created = false;
Mikhail Naganov289468a2023-03-29 10:06:15 -0700716 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
717 s, destinationPortIds, &portConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800718 if (created) {
719 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, portConfig.id);
720 }
721 ids->push_back(portConfig.id);
Mikhail Naganov289468a2023-03-29 10:06:15 -0700722 if (portIds != nullptr) {
723 portIds->insert(portConfig.portId);
724 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800725 }
726 return OK;
727 };
Mikhail Naganov289468a2023-03-29 10:06:15 -0700728 // When looking up port configs, the destinationPortId is only used for mix ports.
729 // Thus, we process device port configs first, and look up the destination port ID from them.
730 bool sourceIsDevice = std::any_of(aidlSources.begin(), aidlSources.end(),
731 [](const auto& config) { return config.ext.getTag() == AudioPortExt::device; });
732 const std::vector<AudioPortConfig>& devicePortConfigs =
733 sourceIsDevice ? aidlSources : aidlSinks;
734 std::vector<int32_t>* devicePortConfigIds =
735 sourceIsDevice ? &aidlPatch.sourcePortConfigIds : &aidlPatch.sinkPortConfigIds;
736 const std::vector<AudioPortConfig>& mixPortConfigs =
737 sourceIsDevice ? aidlSinks : aidlSources;
738 std::vector<int32_t>* mixPortConfigIds =
739 sourceIsDevice ? &aidlPatch.sinkPortConfigIds : &aidlPatch.sourcePortConfigIds;
740 std::set<int32_t> devicePortIds;
741 RETURN_STATUS_IF_ERROR(fillPortConfigs(
742 devicePortConfigs, std::set<int32_t>(), devicePortConfigIds, &devicePortIds));
743 RETURN_STATUS_IF_ERROR(fillPortConfigs(
744 mixPortConfigs, devicePortIds, mixPortConfigIds, nullptr));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800745 if (existingPatchIt != mPatches.end()) {
746 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
747 mModule->setAudioPatch(aidlPatch, &aidlPatch)));
748 existingPatchIt->second = aidlPatch;
749 } else {
750 bool created = false;
751 RETURN_STATUS_IF_ERROR(findOrCreatePatch(aidlPatch, &aidlPatch, &created));
752 // Since no cleanup of the patch is needed, 'created' is ignored.
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800753 halPatchId = aidlPatch.id;
754 *patch = static_cast<audio_patch_handle_t>(halPatchId);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800755 }
756 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000757 return OK;
758}
759
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800760status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800761 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000762 TIME_CHECK();
763 if (!mModule) return NO_INIT;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800764 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
765 if (patch == AUDIO_PATCH_HANDLE_NONE) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800766 return BAD_VALUE;
767 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800768 int32_t halPatchId = static_cast<int32_t>(patch);
769 auto patchIt = mPatches.find(halPatchId);
770 if (patchIt == mPatches.end()) {
771 ALOGE("%s: patch with id %d not found", __func__, halPatchId);
772 return BAD_VALUE;
773 }
774 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->resetAudioPatch(halPatchId)));
775 mPatches.erase(patchIt);
Shunkai Yao51202502022-12-12 06:11:46 +0000776 return OK;
777}
778
Mikhail Naganove93a0862023-03-15 17:06:59 -0700779status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
780 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000781 TIME_CHECK();
782 if (!mModule) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700783 if (port == nullptr) {
784 return BAD_VALUE;
785 }
786 audio_port_v7 portV7;
787 audio_populate_audio_port_v7(port, &portV7);
788 RETURN_STATUS_IF_ERROR(getAudioPort(&portV7));
789 return audio_populate_audio_port(&portV7, port) ? OK : BAD_VALUE;
790}
791
792status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
793 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
794 TIME_CHECK();
795 if (!mModule) return NO_INIT;
796 if (port == nullptr) {
797 return BAD_VALUE;
798 }
799 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
800 ::aidl::android::AudioPortDirection::INPUT;
801 auto aidlPort = VALUE_OR_RETURN_STATUS(
802 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
803 if (aidlPort.ext.getTag() != AudioPortExt::device) {
804 ALOGE("%s: provided port is not a device port (module %s): %s",
805 __func__, mInstance.c_str(), aidlPort.toString().c_str());
806 return BAD_VALUE;
807 }
808 const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
809 // It seems that we don't have to call HAL since all valid ports have been added either
810 // during initialization, or while handling connection of an external device.
811 auto portsIt = findPort(matchDevice);
812 if (portsIt == mPorts.end()) {
813 ALOGE("%s: device port for device %s is not found in the module %s",
814 __func__, matchDevice.toString().c_str(), mInstance.c_str());
815 return BAD_VALUE;
816 }
817 const int32_t fwkId = aidlPort.id;
818 aidlPort = portsIt->second;
819 aidlPort.id = fwkId;
820 *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
821 aidlPort, isInput));
822 return OK;
823}
824
825status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
826 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
827 TIME_CHECK();
828 if (!mModule) return NO_INIT;
829 if (config == nullptr) {
830 return BAD_VALUE;
831 }
832 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
833 config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
834 AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
835 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
836 *config, isInput, 0 /*portId*/));
837 AudioPortConfig portConfig;
838 bool created = false;
Mikhail Naganov289468a2023-03-29 10:06:15 -0700839 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
840 requestedPortConfig, std::set<int32_t>(), &portConfig, &created));
Shunkai Yao51202502022-12-12 06:11:46 +0000841 return OK;
842}
843
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800844MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
845 if (mMicrophones.status == Microphones::Status::UNKNOWN) {
846 TIME_CHECK();
847 std::vector<MicrophoneInfo> aidlInfo;
848 status_t status = statusTFromBinderStatus(mModule->getMicrophones(&aidlInfo));
849 if (status == OK) {
850 mMicrophones.status = Microphones::Status::QUERIED;
851 mMicrophones.info = std::move(aidlInfo);
852 } else if (status == INVALID_OPERATION) {
853 mMicrophones.status = Microphones::Status::NOT_SUPPORTED;
854 } else {
855 ALOGE("%s: Unexpected status from 'IModule.getMicrophones': %d", __func__, status);
856 return {};
857 }
858 }
859 if (mMicrophones.status == Microphones::Status::QUERIED) {
860 return &mMicrophones.info;
861 }
862 return {}; // NOT_SUPPORTED
863}
864
Shunkai Yao51202502022-12-12 06:11:46 +0000865status_t DeviceHalAidl::getMicrophones(
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800866 std::vector<audio_microphone_characteristic_t>* microphones) {
867 if (!microphones) {
868 return BAD_VALUE;
869 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000870 TIME_CHECK();
871 if (!mModule) return NO_INIT;
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800872 auto staticInfo = getMicrophoneInfo();
873 if (!staticInfo) return INVALID_OPERATION;
874 std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
875 emptyDynamicInfo.reserve(staticInfo->size());
876 std::transform(staticInfo->begin(), staticInfo->end(), std::back_inserter(emptyDynamicInfo),
877 [](const auto& info) { return MicrophoneDynamicInfo{ .id = info.id }; });
878 *microphones = VALUE_OR_RETURN_STATUS(
879 ::aidl::android::convertContainers<std::vector<audio_microphone_characteristic_t>>(
880 *staticInfo, emptyDynamicInfo,
881 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t)
882 );
Shunkai Yao51202502022-12-12 06:11:46 +0000883 return OK;
884}
885
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700886status_t DeviceHalAidl::addDeviceEffect(
887 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
888 TIME_CHECK();
889 if (!mModule) return NO_INIT;
Shunkai Yao51202502022-12-12 06:11:46 +0000890 if (!effect) {
891 return BAD_VALUE;
892 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700893 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
894 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
895 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
896 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
897 *device, isInput, 0));
898 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
899 ALOGE("%s: provided port config is not a device port config: %s",
900 __func__, requestedPortConfig.toString().c_str());
901 return BAD_VALUE;
902 }
903 AudioPortConfig devicePortConfig;
904 bool created;
905 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
906 requestedPortConfig, {} /*destinationPortIds*/, &devicePortConfig, &created));
907 Cleanups cleanups;
908 if (created) {
909 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
910 }
911 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
912 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->addDeviceEffect(
913 devicePortConfig.id, aidlEffect->getIEffect())));
914 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000915 return OK;
916}
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700917status_t DeviceHalAidl::removeDeviceEffect(
918 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
919 TIME_CHECK();
920 if (!mModule) return NO_INIT;
Shunkai Yao51202502022-12-12 06:11:46 +0000921 if (!effect) {
922 return BAD_VALUE;
923 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700924 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
925 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
926 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
927 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
928 *device, isInput, 0));
929 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
930 ALOGE("%s: provided port config is not a device port config: %s",
931 __func__, requestedPortConfig.toString().c_str());
932 return BAD_VALUE;
933 }
934 auto existingPortConfigIt = findPortConfig(
935 requestedPortConfig.ext.get<AudioPortExt::Tag::device>().device);
936 if (existingPortConfigIt == mPortConfigs.end()) {
937 ALOGE("%s: could not find a configured device port for the config %s",
938 __func__, requestedPortConfig.toString().c_str());
939 return BAD_VALUE;
940 }
941 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
942 return statusTFromBinderStatus(mModule->removeDeviceEffect(
943 existingPortConfigIt->first, aidlEffect->getIEffect()));
Shunkai Yao51202502022-12-12 06:11:46 +0000944}
945
946status_t DeviceHalAidl::getMmapPolicyInfos(
David Li9cf5e622023-03-21 00:51:10 +0800947 media::audio::common::AudioMMapPolicyType policyType,
948 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000949 TIME_CHECK();
Mikhail Naganov25bc9a22023-04-21 18:48:16 -0700950 AudioMMapPolicyType mmapPolicyType = VALUE_OR_RETURN_STATUS(
951 cpp2ndk_AudioMMapPolicyType(policyType));
David Li9cf5e622023-03-21 00:51:10 +0800952
953 std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
954
955 if (status_t status = statusTFromBinderStatus(
956 mModule->getMmapPolicyInfos(mmapPolicyType, &mmapPolicyInfos)); status != OK) {
957 return status;
958 }
959
960 *policyInfos = VALUE_OR_RETURN_STATUS(
961 convertContainer<std::vector<media::audio::common::AudioMMapPolicyInfo>>(
962 mmapPolicyInfos, ndk2cpp_AudioMMapPolicyInfo));
Shunkai Yao51202502022-12-12 06:11:46 +0000963 return OK;
964}
965
966int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000967 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800968 int32_t mixerBurstCount = 0;
969 if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
970 return mixerBurstCount;
971 }
972 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000973}
974
975int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000976 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800977 int32_t hardwareBurstMinUsec = 0;
978 if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
979 return hardwareBurstMinUsec;
980 }
981 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000982}
983
984error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000985 TIME_CHECK();
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700986 if (!mModule) return NO_INIT;
987 int32_t aidlHwAvSync;
988 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
989 return VALUE_OR_RETURN_STATUS(
990 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +0000991}
992
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000993status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
994 TIME_CHECK();
995 if (!mModule) return NO_INIT;
996 return mModule->dump(fd, Args(args).args(), args.size());
David Li9cf5e622023-03-21 00:51:10 +0800997}
Shunkai Yao51202502022-12-12 06:11:46 +0000998
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700999int32_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
Mikhail Naganov31d46652023-01-10 18:29:25 +00001000 TIME_CHECK();
Mikhail Naganov3ac95c92023-04-12 13:14:30 -07001001 if (!mModule) return NO_INIT;
1002 if (supports == nullptr) {
1003 return BAD_VALUE;
1004 }
1005 return statusTFromBinderStatus(mModule->supportsVariableLatency(supports));
Shunkai Yao51202502022-12-12 06:11:46 +00001006}
Mikhail Naganov31d46652023-01-10 18:29:25 +00001007
jiabin872de702023-04-27 22:04:31 +00001008
1009status_t DeviceHalAidl::prepareToDisconnectExternalDevice(const struct audio_port_v7* port) {
1010 // There is not AIDL API defined for `prepareToDisconnectExternalDevice`.
1011 // Call `setConnectedState` instead.
1012 // TODO(b/279824103): call prepareToDisconnectExternalDevice when it is added.
1013 const status_t status = setConnectedState(port, false /*connected*/);
1014 if (status == NO_ERROR) {
1015 mDeviceDisconnectionNotified.insert(port->id);
1016 }
1017 return status;
1018}
1019
Mikhail Naganove93a0862023-03-15 17:06:59 -07001020status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
1021 TIME_CHECK();
1022 if (!mModule) return NO_INIT;
1023 if (port == nullptr) {
1024 return BAD_VALUE;
1025 }
jiabin872de702023-04-27 22:04:31 +00001026 if (!connected && mDeviceDisconnectionNotified.erase(port->id) > 0) {
1027 // For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
1028 // and then call `setConnectedState`. However, there is no API for
1029 // `prepareToDisconnectExternalDevice` yet. In that case, `setConnectedState` will be
1030 // called when calling `prepareToDisconnectExternalDevice`. Do not call to the HAL if
1031 // previous call is successful. Also remove the cache here to avoid a large cache after
1032 // a long run.
1033 return NO_ERROR;
1034 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001035 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
1036 ::aidl::android::AudioPortDirection::INPUT;
1037 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
1038 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
1039 if (aidlPort.ext.getTag() != AudioPortExt::device) {
1040 ALOGE("%s: provided port is not a device port (module %s): %s",
1041 __func__, mInstance.c_str(), aidlPort.toString().c_str());
1042 return BAD_VALUE;
1043 }
1044 if (connected) {
1045 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1046 // Reset the device address to find the "template" port.
1047 matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
1048 auto portsIt = findPort(matchDevice);
1049 if (portsIt == mPorts.end()) {
1050 ALOGW("%s: device port for device %s is not found in the module %s",
1051 __func__, matchDevice.toString().c_str(), mInstance.c_str());
1052 return BAD_VALUE;
1053 }
1054 // Use the ID of the "template" port, use all the information from the provided port.
1055 aidlPort.id = portsIt->first;
1056 AudioPort connectedPort;
1057 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
1058 aidlPort, &connectedPort)));
1059 const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
1060 LOG_ALWAYS_FATAL_IF(!inserted,
1061 "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
1062 __func__, mInstance.c_str(), connectedPort.toString().c_str(),
1063 it->second.toString().c_str());
1064 } else { // !connected
1065 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1066 auto portsIt = findPort(matchDevice);
1067 if (portsIt == mPorts.end()) {
1068 ALOGW("%s: device port for device %s is not found in the module %s",
1069 __func__, matchDevice.toString().c_str(), mInstance.c_str());
1070 return BAD_VALUE;
1071 }
1072 // Any streams opened on the external device must be closed by this time,
1073 // thus we can clean up patches and port configs that were created for them.
1074 resetUnusedPatchesAndPortConfigs();
1075 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
1076 portsIt->second.id)));
1077 mPorts.erase(portsIt);
1078 }
Mikhail Naganov289468a2023-03-29 10:06:15 -07001079 return updateRoutes();
Mikhail Naganove93a0862023-03-15 17:06:59 -07001080}
1081
1082status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
1083 TIME_CHECK();
1084 if (!mModule) return NO_INIT;
1085 ModuleDebug debug{ .simulateDeviceConnections = enabled };
1086 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
1087 // This is important to log as it affects HAL behavior.
1088 if (status == OK) {
1089 ALOGI("%s: set enabled: %d", __func__, enabled);
1090 } else {
1091 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
1092 }
1093 return status;
1094}
1095
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001096bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
1097 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1098 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1099}
1100
1101bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
1102 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1103 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1104 return p.portId == mDefaultInputPortId;
1105 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1106 return p.portId == mDefaultOutputPortId;
1107 }
1108 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1109}
1110
David Lia8675d42023-03-30 21:08:06 +08001111status_t DeviceHalAidl::createOrUpdatePortConfig(
1112 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool* created) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001113 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001114 AudioPortConfig appliedPortConfig;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001115 bool applied = false;
1116 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001117 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001118 if (!applied) {
1119 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001120 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001121 if (!applied) {
1122 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001123 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001124 return NO_INIT;
1125 }
1126 }
David Lia8675d42023-03-30 21:08:06 +08001127
1128 int32_t id = appliedPortConfig.id;
1129 if (requestedPortConfig.id != 0 && requestedPortConfig.id != id) {
1130 LOG_ALWAYS_FATAL("%s: requested port config id %d changed to %d", __func__,
1131 requestedPortConfig.id, id);
1132 }
1133
1134 auto [it, inserted] = mPortConfigs.insert_or_assign(std::move(id),
1135 std::move(appliedPortConfig));
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001136 *result = it;
David Lia8675d42023-03-30 21:08:06 +08001137 *created = inserted;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001138 return OK;
1139}
1140
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001141status_t DeviceHalAidl::filterAndRetrieveBtA2dpParameters(
1142 AudioParameter &keys, AudioParameter *result) {
1143 TIME_CHECK();
1144 if (String8 key = String8(AudioParameter::keyReconfigA2dpSupported); keys.containsKey(key)) {
1145 keys.remove(key);
1146 bool supports;
1147 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1148 mBluetoothA2dp->supportsOffloadReconfiguration(&supports)));
1149 result->addInt(key, supports ? 1 : 0);
1150 }
1151 return OK;
1152}
1153
Mikhail Naganovccc82112023-04-27 18:14:15 -07001154status_t DeviceHalAidl::filterAndUpdateBtA2dpParameters(AudioParameter &parameters) {
1155 TIME_CHECK();
1156 std::optional<bool> a2dpEnabled;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001157 std::optional<std::vector<VendorParameter>> reconfigureOffload;
Mikhail Naganovccc82112023-04-27 18:14:15 -07001158 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1159 parameters, String8(AudioParameter::keyBtA2dpSuspended),
1160 [&a2dpEnabled](const String8& trueOrFalse) {
1161 if (trueOrFalse == AudioParameter::valueTrue) {
1162 a2dpEnabled = false; // 'suspended' == true
1163 return OK;
1164 } else if (trueOrFalse == AudioParameter::valueFalse) {
1165 a2dpEnabled = true; // 'suspended' == false
1166 return OK;
1167 }
1168 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1169 AudioParameter::keyBtA2dpSuspended, trueOrFalse.c_str());
1170 return BAD_VALUE;
1171 }));
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001172 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1173 parameters, String8(AudioParameter::keyReconfigA2dp),
1174 [&](const String8& value) -> status_t {
1175 if (mVendorExt != nullptr) {
1176 std::vector<VendorParameter> result;
1177 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1178 mVendorExt->parseBluetoothA2dpReconfigureOffload(
1179 std::string(value.c_str()), &result)));
1180 reconfigureOffload = std::move(result);
1181 } else {
1182 reconfigureOffload = std::vector<VendorParameter>();
1183 }
1184 return OK;
1185 }));
Mikhail Naganovccc82112023-04-27 18:14:15 -07001186 if (mBluetoothA2dp != nullptr && a2dpEnabled.has_value()) {
1187 return statusTFromBinderStatus(mBluetoothA2dp->setEnabled(a2dpEnabled.value()));
1188 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001189 if (mBluetoothA2dp != nullptr && reconfigureOffload.has_value()) {
1190 return statusTFromBinderStatus(mBluetoothA2dp->reconfigureOffload(
1191 reconfigureOffload.value()));
1192 }
Mikhail Naganovccc82112023-04-27 18:14:15 -07001193 return OK;
1194}
1195
1196status_t DeviceHalAidl::filterAndUpdateBtHfpParameters(AudioParameter &parameters) {
1197 TIME_CHECK();
1198 IBluetooth::HfpConfig hfpConfig;
1199 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1200 parameters, String8(AudioParameter::keyBtHfpEnable),
1201 [&hfpConfig](const String8& trueOrFalse) {
1202 if (trueOrFalse == AudioParameter::valueTrue) {
1203 hfpConfig.isEnabled = Boolean{ .value = true };
1204 return OK;
1205 } else if (trueOrFalse == AudioParameter::valueFalse) {
1206 hfpConfig.isEnabled = Boolean{ .value = false };
1207 return OK;
1208 }
1209 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1210 AudioParameter::keyBtHfpEnable, trueOrFalse.c_str());
1211 return BAD_VALUE;
1212 }));
1213 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1214 parameters, String8(AudioParameter::keyBtHfpSamplingRate),
1215 [&hfpConfig](int sampleRate) {
1216 return sampleRate > 0 ?
1217 hfpConfig.sampleRate = Int{ .value = sampleRate }, OK : BAD_VALUE;
1218 }));
1219 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1220 parameters, String8(AudioParameter::keyBtHfpVolume),
1221 [&hfpConfig](int volume0to15) {
1222 if (volume0to15 >= 0 && volume0to15 <= 15) {
1223 hfpConfig.volume = Float{ .value = volume0to15 / 15.0f };
1224 return OK;
1225 }
1226 return BAD_VALUE;
1227 }));
1228 if (mBluetooth != nullptr && hfpConfig != IBluetooth::HfpConfig{}) {
1229 IBluetooth::HfpConfig newHfpConfig;
1230 return statusTFromBinderStatus(mBluetooth->setHfpConfig(hfpConfig, &newHfpConfig));
1231 }
1232 return OK;
1233}
1234
1235status_t DeviceHalAidl::filterAndUpdateBtLeParameters(AudioParameter &parameters) {
1236 TIME_CHECK();
1237 std::optional<bool> leEnabled;
1238 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1239 parameters, String8(AudioParameter::keyBtLeSuspended),
1240 [&leEnabled](const String8& trueOrFalse) {
1241 if (trueOrFalse == AudioParameter::valueTrue) {
1242 leEnabled = false; // 'suspended' == true
1243 return OK;
1244 } else if (trueOrFalse == AudioParameter::valueFalse) {
1245 leEnabled = true; // 'suspended' == false
1246 return OK;
1247 }
1248 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1249 AudioParameter::keyBtLeSuspended, trueOrFalse.c_str());
1250 return BAD_VALUE;
1251 }));
1252 if (mBluetoothLe != nullptr && leEnabled.has_value()) {
1253 return statusTFromBinderStatus(mBluetoothLe->setEnabled(leEnabled.value()));
1254 }
1255 return OK;
1256}
1257
1258status_t DeviceHalAidl::filterAndUpdateBtScoParameters(AudioParameter &parameters) {
1259 TIME_CHECK();
1260 IBluetooth::ScoConfig scoConfig;
1261 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1262 parameters, String8(AudioParameter::keyBtSco),
1263 [&scoConfig](const String8& onOrOff) {
1264 if (onOrOff == AudioParameter::valueOn) {
1265 scoConfig.isEnabled = Boolean{ .value = true };
1266 return OK;
1267 } else if (onOrOff == AudioParameter::valueOff) {
1268 scoConfig.isEnabled = Boolean{ .value = false };
1269 return OK;
1270 }
1271 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1272 AudioParameter::keyBtSco, onOrOff.c_str());
1273 return BAD_VALUE;
1274 }));
1275 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1276 parameters, String8(AudioParameter::keyBtScoHeadsetName),
1277 [&scoConfig](const String8& name) {
1278 scoConfig.debugName = name;
1279 return OK;
1280 }));
1281 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1282 parameters, String8(AudioParameter::keyBtNrec),
1283 [&scoConfig](const String8& onOrOff) {
1284 if (onOrOff == AudioParameter::valueOn) {
1285 scoConfig.isNrecEnabled = Boolean{ .value = true };
1286 return OK;
1287 } else if (onOrOff == AudioParameter::valueOff) {
1288 scoConfig.isNrecEnabled = Boolean{ .value = false };
1289 return OK;
1290 }
1291 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1292 AudioParameter::keyBtNrec, onOrOff.c_str());
1293 return BAD_VALUE;
1294 }));
1295 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1296 parameters, String8(AudioParameter::keyBtScoWb),
1297 [&scoConfig](const String8& onOrOff) {
1298 if (onOrOff == AudioParameter::valueOn) {
1299 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO_WB;
1300 return OK;
1301 } else if (onOrOff == AudioParameter::valueOff) {
1302 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO;
1303 return OK;
1304 }
1305 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1306 AudioParameter::keyBtScoWb, onOrOff.c_str());
1307 return BAD_VALUE;
1308 }));
1309 if (mBluetooth != nullptr && scoConfig != IBluetooth::ScoConfig{}) {
1310 IBluetooth::ScoConfig newScoConfig;
1311 return statusTFromBinderStatus(mBluetooth->setScoConfig(scoConfig, &newScoConfig));
1312 }
1313 return OK;
1314}
1315
Mikhail Naganove92c34b2023-05-31 14:24:48 -07001316status_t DeviceHalAidl::filterAndUpdateScreenParameters(AudioParameter &parameters) {
1317 TIME_CHECK();
1318 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1319 parameters, String8(AudioParameter::keyScreenState),
1320 [&](const String8& onOrOff) -> status_t {
1321 std::optional<bool> isTurnedOn;
1322 if (onOrOff == AudioParameter::valueOn) {
1323 isTurnedOn = true;
1324 } else if (onOrOff == AudioParameter::valueOff) {
1325 isTurnedOn = false;
1326 }
1327 if (!isTurnedOn.has_value()) {
1328 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1329 AudioParameter::keyScreenState, onOrOff.c_str());
1330 return BAD_VALUE;
1331 }
1332 return statusTFromBinderStatus(
1333 mModule->updateScreenState(isTurnedOn.value()));
1334 }));
1335 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1336 parameters, String8(AudioParameter::keyScreenRotation),
1337 [&](int rotationDegrees) -> status_t {
1338 IModule::ScreenRotation rotation;
1339 switch (rotationDegrees) {
1340 case 0: rotation = IModule::ScreenRotation::DEG_0; break;
1341 case 90: rotation = IModule::ScreenRotation::DEG_90; break;
1342 case 180: rotation = IModule::ScreenRotation::DEG_180; break;
1343 case 270: rotation = IModule::ScreenRotation::DEG_270; break;
1344 default:
1345 ALOGE("setParameters: parameter key \"%s\" has invalid value %d",
1346 AudioParameter::keyScreenRotation, rotationDegrees);
1347 return BAD_VALUE;
1348 }
1349 return statusTFromBinderStatus(mModule->updateScreenRotation(rotation));
1350 }));
1351 return OK;
1352}
1353
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001354status_t DeviceHalAidl::findOrCreatePatch(
1355 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
1356 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
1357 requestedPatch.sourcePortConfigIds.end());
1358 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
1359 requestedPatch.sinkPortConfigIds.end());
1360 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
1361}
1362
1363status_t DeviceHalAidl::findOrCreatePatch(
1364 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
1365 AudioPatch* patch, bool* created) {
1366 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
1367 if (patchIt == mPatches.end()) {
1368 TIME_CHECK();
1369 AudioPatch requestedPatch, appliedPatch;
1370 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
1371 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
1372 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
1373 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
1374 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
1375 requestedPatch, &appliedPatch)));
1376 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
1377 *created = true;
1378 } else {
1379 *created = false;
1380 }
1381 *patch = patchIt->second;
1382 return OK;
1383}
1384
jiabin9c07faf2023-04-26 22:00:44 +00001385status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device, const AudioConfig* config,
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001386 AudioPortConfig* portConfig, bool* created) {
1387 auto portConfigIt = findPortConfig(device);
1388 if (portConfigIt == mPortConfigs.end()) {
1389 auto portsIt = findPort(device);
1390 if (portsIt == mPorts.end()) {
1391 ALOGE("%s: device port for device %s is not found in the module %s",
1392 __func__, device.toString().c_str(), mInstance.c_str());
1393 return BAD_VALUE;
1394 }
1395 AudioPortConfig requestedPortConfig;
1396 requestedPortConfig.portId = portsIt->first;
jiabin9c07faf2023-04-26 22:00:44 +00001397 if (config != nullptr) {
1398 setPortConfigFromConfig(&requestedPortConfig, *config);
1399 }
David Lia8675d42023-03-30 21:08:06 +08001400 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1401 created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001402 } else {
1403 *created = false;
1404 }
1405 *portConfig = portConfigIt->second;
1406 return OK;
1407}
1408
1409status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001410 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001411 AudioSource source, const std::set<int32_t>& destinationPortIds,
1412 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001413 // These flags get removed one by one in this order when retrying port finding.
1414 static const std::vector<AudioInputFlags> kOptionalInputFlags{
1415 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001416 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001417 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001418 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
1419 AudioIoFlags matchFlags = flags.value();
Mikhail Naganov289468a2023-03-29 10:06:15 -07001420 auto portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001421 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
1422 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
1423 if (!isBitPositionFlagSet(
1424 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
1425 ++optionalInputFlagsIt;
1426 continue;
1427 }
1428 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
1429 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
Mikhail Naganov289468a2023-03-29 10:06:15 -07001430 portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001431 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
1432 "retried with flags %s", __func__, config.toString().c_str(),
1433 flags.value().toString().c_str(), mInstance.c_str(),
1434 matchFlags.toString().c_str());
1435 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001436 if (portsIt == mPorts.end()) {
1437 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001438 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001439 mInstance.c_str());
1440 return BAD_VALUE;
1441 }
1442 AudioPortConfig requestedPortConfig;
1443 requestedPortConfig.portId = portsIt->first;
1444 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001445 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001446 if (matchFlags.getTag() == AudioIoFlags::Tag::input
1447 && source != AudioSource::SYS_RESERVED_INVALID) {
1448 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
1449 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
1450 }
David Lia8675d42023-03-30 21:08:06 +08001451 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1452 created));
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001453 } else if (!flags.has_value()) {
1454 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
1455 "and was not created as flags are not specified",
1456 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
1457 return BAD_VALUE;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001458 } else {
David Lia8675d42023-03-30 21:08:06 +08001459 AudioPortConfig requestedPortConfig = portConfigIt->second;
1460 if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
1461 AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
1462 if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
1463 source != AudioSource::SYS_RESERVED_INVALID) {
1464 mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
1465 }
1466 }
1467
1468 if (requestedPortConfig != portConfigIt->second) {
1469 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1470 created));
1471 } else {
1472 *created = false;
1473 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001474 }
1475 *portConfig = portConfigIt->second;
1476 return OK;
1477}
1478
1479status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001480 const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
1481 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001482 using Tag = AudioPortExt::Tag;
1483 if (requestedPortConfig.ext.getTag() == Tag::mix) {
1484 if (const auto& p = requestedPortConfig;
1485 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001486 !p.format.has_value()) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001487 ALOGW("%s: provided mix port config is not fully specified: %s",
1488 __func__, p.toString().c_str());
1489 return BAD_VALUE;
1490 }
1491 AudioConfig config;
1492 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001493 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
1494 AudioPortMixExtUseCase::Tag::source ?
1495 requestedPortConfig.ext.get<Tag::mix>().usecase.
1496 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001497 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001498 requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
1499 portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001500 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
1501 return findOrCreatePortConfig(
jiabin9c07faf2023-04-26 22:00:44 +00001502 requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
1503 portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001504 }
1505 ALOGW("%s: unsupported audio port config: %s",
1506 __func__, requestedPortConfig.toString().c_str());
1507 return BAD_VALUE;
1508}
1509
1510DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
1511 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
1512 return std::find_if(mPatches.begin(), mPatches.end(),
1513 [&](const auto& pair) {
1514 const auto& p = pair.second;
1515 std::set<int32_t> patchSrcs(
1516 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
1517 std::set<int32_t> patchSinks(
1518 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
1519 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
1520}
1521
1522DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001523 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1524 return mPorts.find(mDefaultInputPortId);
1525 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1526 return mPorts.find(mDefaultOutputPortId);
1527 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001528 return std::find_if(mPorts.begin(), mPorts.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001529 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001530}
1531
1532DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001533 const AudioConfig& config, const AudioIoFlags& flags,
1534 const std::set<int32_t>& destinationPortIds) {
Mikhail Naganove93a0862023-03-15 17:06:59 -07001535 auto belongsToProfile = [&config](const AudioProfile& prof) {
1536 return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
1537 (config.base.channelMask.getTag() == AudioChannelLayout::none ||
1538 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
1539 config.base.channelMask) != prof.channelMasks.end()) &&
1540 (config.base.sampleRate == 0 ||
1541 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
1542 config.base.sampleRate) != prof.sampleRates.end());
1543 };
jiabin9c07faf2023-04-26 22:00:44 +00001544 static const std::vector<AudioOutputFlags> kOptionalOutputFlags{AudioOutputFlags::BIT_PERFECT};
1545 int optionalFlags = 0;
1546 auto flagMatches = [&flags, &optionalFlags](const AudioIoFlags& portFlags) {
1547 // Ports should be able to match if the optional flags are not requested.
1548 return portFlags == flags ||
1549 (portFlags.getTag() == AudioIoFlags::Tag::output &&
1550 AudioIoFlags::make<AudioIoFlags::Tag::output>(
1551 portFlags.get<AudioIoFlags::Tag::output>() &
1552 ~optionalFlags) == flags);
1553 };
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001554 auto matcher = [&](const auto& pair) {
1555 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001556 return p.ext.getTag() == AudioPortExt::Tag::mix &&
jiabin9c07faf2023-04-26 22:00:44 +00001557 flagMatches(p.flags) &&
Mikhail Naganov289468a2023-03-29 10:06:15 -07001558 (destinationPortIds.empty() ||
1559 std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
1560 [&](const int32_t destId) { return mRoutingMatrix.count(
1561 std::make_pair(p.id, destId)) != 0; })) &&
Mikhail Naganove93a0862023-03-15 17:06:59 -07001562 (p.profiles.empty() ||
1563 std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
1564 p.profiles.end()); };
jiabin9c07faf2023-04-26 22:00:44 +00001565 auto result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1566 if (result == mPorts.end() && flags.getTag() == AudioIoFlags::Tag::output) {
1567 auto optionalOutputFlagsIt = kOptionalOutputFlags.begin();
1568 while (result == mPorts.end() && optionalOutputFlagsIt != kOptionalOutputFlags.end()) {
1569 if (isBitPositionFlagSet(
1570 flags.get<AudioIoFlags::Tag::output>(), *optionalOutputFlagsIt)) {
1571 // If the flag is set by the request, it must be matched.
1572 ++optionalOutputFlagsIt;
1573 continue;
1574 }
1575 optionalFlags |= makeBitPositionFlagMask(*optionalOutputFlagsIt++);
1576 result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1577 ALOGI("%s: port for config %s, flags %s was not found in the module %s, "
1578 "retried with excluding optional flags %#x", __func__, config.toString().c_str(),
1579 flags.toString().c_str(), mInstance.c_str(), optionalFlags);
1580 }
1581 }
1582 return result;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001583}
1584
1585DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001586 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001587 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001588}
1589
1590DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001591 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001592 using Tag = AudioPortExt::Tag;
1593 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
1594 [&](const auto& pair) {
1595 const auto& p = pair.second;
1596 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
1597 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
1598 !p.format.has_value() || !p.flags.has_value(),
1599 "%s: stored mix port config is not fully specified: %s",
1600 __func__, p.toString().c_str());
1601 return p.ext.getTag() == Tag::mix &&
1602 isConfigEqualToPortConfig(config, p) &&
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001603 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001604 p.ext.template get<Tag::mix>().handle == ioHandle; });
1605}
Mikhail Naganove93a0862023-03-15 17:06:59 -07001606
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001607void DeviceHalAidl::resetPatch(int32_t patchId) {
1608 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1609 mPatches.erase(it);
1610 TIME_CHECK();
1611 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1612 ALOGE("%s: error while resetting patch %d: %s",
1613 __func__, patchId, status.getDescription().c_str());
1614 }
1615 return;
1616 }
1617 ALOGE("%s: patch id %d not found", __func__, patchId);
1618}
1619
1620void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1621 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1622 mPortConfigs.erase(it);
1623 TIME_CHECK();
1624 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1625 !status.isOk()) {
1626 ALOGE("%s: error while resetting port config %d: %s",
1627 __func__, portConfigId, status.getDescription().c_str());
1628 }
1629 return;
1630 }
1631 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1632}
1633
Mikhail Naganove93a0862023-03-15 17:06:59 -07001634void DeviceHalAidl::resetUnusedPatches() {
1635 // Since patches can be created independently of streams via 'createAudioPatch',
1636 // here we only clean up patches for released streams.
1637 for (auto it = mStreams.begin(); it != mStreams.end(); ) {
1638 if (auto streamSp = it->first.promote(); streamSp) {
1639 ++it;
1640 } else {
1641 resetPatch(it->second);
1642 it = mStreams.erase(it);
1643 }
1644 }
1645}
1646
1647void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
1648 resetUnusedPatches();
1649 resetUnusedPortConfigs();
1650}
1651
1652void DeviceHalAidl::resetUnusedPortConfigs() {
1653 // The assumption is that port configs are used to create patches
1654 // (or to open streams, but that involves creation of patches, too). Thus,
1655 // orphaned port configs can and should be reset.
1656 std::set<int32_t> portConfigIds;
1657 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
1658 std::inserter(portConfigIds, portConfigIds.end()),
1659 [](const auto& pcPair) { return pcPair.first; });
1660 for (const auto& p : mPatches) {
1661 for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
1662 for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
1663 }
jiabin9c07faf2023-04-26 22:00:44 +00001664 for (int32_t id : mInitialPortConfigIds) {
1665 portConfigIds.erase(id);
1666 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001667 for (int32_t id : portConfigIds) resetPortConfig(id);
1668}
1669
Mikhail Naganov289468a2023-03-29 10:06:15 -07001670status_t DeviceHalAidl::updateRoutes() {
1671 TIME_CHECK();
Mikhail Naganov289468a2023-03-29 10:06:15 -07001672 RETURN_STATUS_IF_ERROR(
Mikhail Naganovf83b9742023-04-24 13:06:04 -07001673 statusTFromBinderStatus(mModule->getAudioRoutes(&mRoutes)));
1674 ALOGW_IF(mRoutes.empty(), "%s: module %s returned an empty list of audio routes",
Mikhail Naganov289468a2023-03-29 10:06:15 -07001675 __func__, mInstance.c_str());
1676 mRoutingMatrix.clear();
Mikhail Naganovf83b9742023-04-24 13:06:04 -07001677 for (const auto& r : mRoutes) {
Mikhail Naganov289468a2023-03-29 10:06:15 -07001678 for (auto portId : r.sourcePortIds) {
1679 mRoutingMatrix.emplace(r.sinkPortId, portId);
1680 mRoutingMatrix.emplace(portId, r.sinkPortId);
1681 }
1682 }
1683 return OK;
1684}
1685
Mikhail Naganovdfd594e2023-02-08 16:59:41 -08001686void DeviceHalAidl::clearCallbacks(void* cookie) {
1687 std::lock_guard l(mLock);
1688 mCallbacks.erase(cookie);
1689}
1690
1691sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1692 return getCallbackImpl(cookie, &Callbacks::out);
1693}
1694
1695void DeviceHalAidl::setStreamOutCallback(
1696 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1697 setCallbackImpl(cookie, &Callbacks::out, cb);
1698}
1699
1700sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1701 void* cookie) {
1702 return getCallbackImpl(cookie, &Callbacks::event);
1703}
1704
1705void DeviceHalAidl::setStreamOutEventCallback(
1706 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1707 setCallbackImpl(cookie, &Callbacks::event, cb);
1708}
1709
1710sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1711 void* cookie) {
1712 return getCallbackImpl(cookie, &Callbacks::latency);
1713}
1714
1715void DeviceHalAidl::setStreamOutLatencyModeCallback(
1716 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1717 setCallbackImpl(cookie, &Callbacks::latency, cb);
1718}
1719
1720template<class C>
1721sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1722 std::lock_guard l(mLock);
1723 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1724 return ((it->second).*field).promote();
1725 }
1726 return nullptr;
1727}
1728template<class C>
1729void DeviceHalAidl::setCallbackImpl(
1730 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1731 std::lock_guard l(mLock);
1732 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1733 (it->second).*field = cb;
1734 }
1735}
1736
Mikhail Naganov31d46652023-01-10 18:29:25 +00001737} // namespace android