blob: ae151908c522b3c05af33329472d7219dd0bb439 [file] [log] [blame]
Shunkai Yao51202502022-12-12 06:11:46 +00001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "DeviceHalAidl"
Vlad Popa03bd5bc2023-01-17 16:16:51 +010018// #define LOG_NDEBUG 0
Shunkai Yao51202502022-12-12 06:11:46 +000019
Mikhail Naganovf56ce782023-01-25 11:29:11 -080020#include <algorithm>
21#include <forward_list>
22
Mikhail Naganovb0c55252023-02-08 16:59:41 -080023#include <aidl/android/hardware/audio/core/BnStreamCallback.h>
24#include <aidl/android/hardware/audio/core/BnStreamOutEventCallback.h>
Mikhail Naganovfab697c2023-01-11 19:33:13 +000025#include <aidl/android/hardware/audio/core/StreamDescriptor.h>
26#include <error/expected_utils.h>
27#include <media/AidlConversionCppNdk.h>
Mikhail Naganovbfbb75b2023-04-21 18:48:16 -070028#include <media/AidlConversionNdkCpp.h>
Mikhail Naganovfab697c2023-01-11 19:33:13 +000029#include <media/AidlConversionUtil.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000030#include <mediautils/TimeCheck.h>
Mikhail Naganov8bd806e2023-01-30 12:33:18 -080031#include <Utils.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000032#include <utils/Log.h>
Shunkai Yao51202502022-12-12 06:11:46 +000033
Mikhail Naganov31d46652023-01-10 18:29:25 +000034#include "DeviceHalAidl.h"
Mikhail Naganova82a69d2023-06-14 16:31:32 -070035#include "EffectHalAidl.h"
Mikhail Naganov31d46652023-01-10 18:29:25 +000036#include "StreamHalAidl.h"
37
Mikhail Naganovfab697c2023-01-11 19:33:13 +000038using aidl::android::aidl_utils::statusTFromBinderStatus;
Mikhail Naganov27382bb2023-04-27 18:14:15 -070039using aidl::android::media::audio::common::Boolean;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -070040using aidl::android::media::audio::common::AudioChannelLayout;
Mikhail Naganovf56ce782023-01-25 11:29:11 -080041using aidl::android::media::audio::common::AudioConfig;
42using aidl::android::media::audio::common::AudioDevice;
David Li9cf5e622023-03-21 00:51:10 +080043using aidl::android::media::audio::common::AudioDeviceAddress;
Mikhail Naganov8bd806e2023-01-30 12:33:18 -080044using aidl::android::media::audio::common::AudioDeviceType;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -070045using aidl::android::media::audio::common::AudioFormatType;
Mikhail Naganov8bd806e2023-01-30 12:33:18 -080046using aidl::android::media::audio::common::AudioInputFlags;
Mikhail Naganovf56ce782023-01-25 11:29:11 -080047using aidl::android::media::audio::common::AudioIoFlags;
Mikhail Naganovb0c55252023-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 Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovb1ddbb02023-03-15 17:06:59 -070060using aidl::android::media::audio::common::AudioProfile;
Mikhail Naganovf56ce782023-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 Naganovb1ddbb02023-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 Naganovf56ce782023-01-25 11:29:11 -080071using aidl::android::hardware::audio::common::RecordTrackMetadata;
72using aidl::android::hardware::audio::core::AudioPatch;
Mikhail Naganovecfafb72023-03-29 10:06:15 -070073using aidl::android::hardware::audio::core::AudioRoute;
Mikhail Naganov27382bb2023-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 Naganovb1ddbb02023-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 Naganovf56ce782023-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 Naganov2d814892023-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;
114 return cpp;
115}
116
Mikhail Naganovffd97712023-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 Naganovf56ce782023-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 Naganovffd97712023-05-03 17:45:36 -0700133 : ConversionHelperAidl("DeviceHalAidl"),
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700134 mInstance(instance), mModule(module), mVendorExt(vext),
Mikhail Naganov27382bb2023-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 Naganovffd97712023-05-03 17:45:36 -0700139}
140
Mikhail Naganov2d814892023-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 Naganov2d814892023-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 Naganovffd97712023-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 Naganovf56ce782023-01-25 11:29:11 -0800175 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000176 if (mModule == nullptr) return NO_INIT;
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800177 std::vector<AudioPort> ports;
Mikhail Naganov2d814892023-04-24 13:06:04 -0700178 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
Mikhail Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovecfafb72023-03-29 10:06:15 -0700198 RETURN_STATUS_IF_ERROR(updateRoutes());
Mikhail Naganovf56ce782023-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); });
jiabin2248fa12023-04-27 22:04:16 +0000205 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
206 std::inserter(mInitialPortConfigIds, mInitialPortConfigIds.end()),
207 [](const auto& pcPair) { return pcPair.first; });
Mikhail Naganovf56ce782023-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 Naganovffd97712023-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 Naganovffd97712023-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 Naganov27382bb2023-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 Naganov27382bb2023-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 Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganov8bd806e2023-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 Naganovb1ddbb02023-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 Naganovb1ddbb02023-03-15 17:06:59 -0700362 &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov8bd806e2023-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 Naganovf56ce782023-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 Naganov8bd806e2023-01-30 12:33:18 -0800372 Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
Mikhail Naganovb1ddbb02023-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());
jiabin2248fa12023-04-27 22:04:16 +0000378 resetUnusedPatchesAndPortConfigs();
Mikhail Naganovf56ce782023-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;
jiabin2248fa12023-04-27 22:04:16 +0000384 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, aidlConfig,
385 &devicePortConfig, &created));
Mikhail Naganovf56ce782023-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 Naganovecfafb72023-03-29 10:06:15 -0700390 std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800391 if (created) {
392 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
393 }
394 setConfigFromPortConfig(aidlConfig, *mixPortConfig);
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800395 if (isInput) {
396 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700397 {devicePortConfig.id}, {mixPortConfig->id}, aidlPatch, &created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800398 } else {
399 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700400 {mixPortConfig->id}, {devicePortConfig.id}, aidlPatch, &created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800401 }
402 if (created) {
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700403 cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, aidlPatch->id);
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800404 }
405 if (aidlConfig->frameCount <= 0) {
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700406 aidlConfig->frameCount = aidlPatch->minimumStreamBufferSizeFrames;
Mikhail Naganovf56ce782023-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 Naganovb0c55252023-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 Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovf56ce782023-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 Naganovb1ddbb02023-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 Naganovb1ddbb02023-03-15 17:06:59 -0700555 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800556 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
557 args.portConfigId = mixPortConfig.id;
Mikhail Naganovb0c55252023-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 Naganovf56ce782023-01-25 11:29:11 -0800569 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovb0c55252023-02-08 16:59:41 -0800570 args.eventCallback = eventCb;
Mikhail Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovb1ddbb02023-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 Naganovb1ddbb02023-03-15 17:06:59 -0700581 mStreams.insert(std::pair(*outStream, aidlPatch.id));
Mikhail Naganovb0c55252023-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 Naganovf56ce782023-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 Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovf56ce782023-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 Naganovb1ddbb02023-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 Naganovb1ddbb02023-03-15 17:06:59 -0700620 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovb1ddbb02023-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 Naganovb1ddbb02023-03-15 17:06:59 -0700642 mStreams.insert(std::pair(*inStream, aidlPatch.id));
Mikhail Naganovf56ce782023-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 Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovf56ce782023-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 Naganovf56ce782023-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 Naganovf56ce782023-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 Naganovf56ce782023-01-25 11:29:11 -0800705 }
Mikhail Naganov8bd806e2023-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 Naganovf56ce782023-01-25 11:29:11 -0800709 auto fillPortConfigs = [&](
Mikhail Naganovecfafb72023-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 Naganovf56ce782023-01-25 11:29:11 -0800713 for (const auto& s : configs) {
714 AudioPortConfig portConfig;
715 bool created = false;
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700716 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
717 s, destinationPortIds, &portConfig, &created));
Mikhail Naganovf56ce782023-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 Naganovecfafb72023-03-29 10:06:15 -0700722 if (portIds != nullptr) {
723 portIds->insert(portConfig.portId);
724 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800725 }
726 return OK;
727 };
Mikhail Naganovecfafb72023-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 Naganovf56ce782023-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 Naganovf56ce782023-01-25 11:29:11 -0800755 }
756 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000757 return OK;
758}
759
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800760status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov8bd806e2023-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 Naganovf56ce782023-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 Naganovb1ddbb02023-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 Naganovb1ddbb02023-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 Naganovecfafb72023-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 Naganovbfbb75b2023-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
Vlad Popa03bd5bc2023-01-17 16:16:51 +01001008status_t DeviceHalAidl::getSoundDoseInterface(const std::string& module,
1009 ::ndk::SpAIBinder* soundDoseBinder) {
1010 TIME_CHECK();
1011 if (!mModule) return NO_INIT;
1012 if (mSoundDose == nullptr) {
1013 ndk::ScopedAStatus status = mModule->getSoundDose(&mSoundDose);
1014 if (!status.isOk()) {
1015 ALOGE("%s failed to return the sound dose interface for module %s: %s",
1016 __func__,
1017 module.c_str(),
1018 status.getDescription().c_str());
1019 return BAD_VALUE;
1020 }
1021 }
1022 *soundDoseBinder = mSoundDose->asBinder();
1023 ALOGI("%s using audio AIDL HAL sound dose interface", __func__);
1024
1025 return OK;
1026}
1027
jiabinc0048632023-04-27 22:04:31 +00001028status_t DeviceHalAidl::prepareToDisconnectExternalDevice(const struct audio_port_v7* port) {
1029 // There is not AIDL API defined for `prepareToDisconnectExternalDevice`.
1030 // Call `setConnectedState` instead.
1031 // TODO(b/279824103): call prepareToDisconnectExternalDevice when it is added.
1032 const status_t status = setConnectedState(port, false /*connected*/);
1033 if (status == NO_ERROR) {
1034 mDeviceDisconnectionNotified.insert(port->id);
1035 }
1036 return status;
1037}
1038
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001039status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
1040 TIME_CHECK();
1041 if (!mModule) return NO_INIT;
1042 if (port == nullptr) {
1043 return BAD_VALUE;
1044 }
jiabinc0048632023-04-27 22:04:31 +00001045 if (!connected && mDeviceDisconnectionNotified.erase(port->id) > 0) {
1046 // For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
1047 // and then call `setConnectedState`. However, there is no API for
1048 // `prepareToDisconnectExternalDevice` yet. In that case, `setConnectedState` will be
1049 // called when calling `prepareToDisconnectExternalDevice`. Do not call to the HAL if
1050 // previous call is successful. Also remove the cache here to avoid a large cache after
1051 // a long run.
1052 return NO_ERROR;
1053 }
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001054 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
1055 ::aidl::android::AudioPortDirection::INPUT;
1056 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
1057 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
1058 if (aidlPort.ext.getTag() != AudioPortExt::device) {
1059 ALOGE("%s: provided port is not a device port (module %s): %s",
1060 __func__, mInstance.c_str(), aidlPort.toString().c_str());
1061 return BAD_VALUE;
1062 }
1063 if (connected) {
1064 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1065 // Reset the device address to find the "template" port.
1066 matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
1067 auto portsIt = findPort(matchDevice);
1068 if (portsIt == mPorts.end()) {
1069 ALOGW("%s: device port for device %s is not found in the module %s",
1070 __func__, matchDevice.toString().c_str(), mInstance.c_str());
1071 return BAD_VALUE;
1072 }
1073 // Use the ID of the "template" port, use all the information from the provided port.
1074 aidlPort.id = portsIt->first;
1075 AudioPort connectedPort;
1076 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
1077 aidlPort, &connectedPort)));
1078 const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
1079 LOG_ALWAYS_FATAL_IF(!inserted,
1080 "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
1081 __func__, mInstance.c_str(), connectedPort.toString().c_str(),
1082 it->second.toString().c_str());
1083 } else { // !connected
1084 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1085 auto portsIt = findPort(matchDevice);
1086 if (portsIt == mPorts.end()) {
1087 ALOGW("%s: device port for device %s is not found in the module %s",
1088 __func__, matchDevice.toString().c_str(), mInstance.c_str());
1089 return BAD_VALUE;
1090 }
1091 // Any streams opened on the external device must be closed by this time,
1092 // thus we can clean up patches and port configs that were created for them.
1093 resetUnusedPatchesAndPortConfigs();
1094 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
1095 portsIt->second.id)));
1096 mPorts.erase(portsIt);
1097 }
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001098 return updateRoutes();
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001099}
1100
1101status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
1102 TIME_CHECK();
1103 if (!mModule) return NO_INIT;
1104 ModuleDebug debug{ .simulateDeviceConnections = enabled };
1105 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
1106 // This is important to log as it affects HAL behavior.
1107 if (status == OK) {
1108 ALOGI("%s: set enabled: %d", __func__, enabled);
1109 } else {
1110 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
1111 }
1112 return status;
1113}
1114
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001115bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
1116 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1117 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1118}
1119
1120bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
1121 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1122 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1123 return p.portId == mDefaultInputPortId;
1124 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1125 return p.portId == mDefaultOutputPortId;
1126 }
1127 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1128}
1129
David Lia8f1e582023-03-30 21:08:06 +08001130status_t DeviceHalAidl::createOrUpdatePortConfig(
1131 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool* created) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001132 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001133 AudioPortConfig appliedPortConfig;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001134 bool applied = false;
1135 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001136 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001137 if (!applied) {
1138 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001139 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001140 if (!applied) {
1141 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001142 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001143 return NO_INIT;
1144 }
1145 }
David Lia8f1e582023-03-30 21:08:06 +08001146
1147 int32_t id = appliedPortConfig.id;
1148 if (requestedPortConfig.id != 0 && requestedPortConfig.id != id) {
1149 LOG_ALWAYS_FATAL("%s: requested port config id %d changed to %d", __func__,
1150 requestedPortConfig.id, id);
1151 }
1152
1153 auto [it, inserted] = mPortConfigs.insert_or_assign(std::move(id),
1154 std::move(appliedPortConfig));
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001155 *result = it;
David Lia8f1e582023-03-30 21:08:06 +08001156 *created = inserted;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001157 return OK;
1158}
1159
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001160status_t DeviceHalAidl::filterAndRetrieveBtA2dpParameters(
1161 AudioParameter &keys, AudioParameter *result) {
1162 TIME_CHECK();
1163 if (String8 key = String8(AudioParameter::keyReconfigA2dpSupported); keys.containsKey(key)) {
1164 keys.remove(key);
1165 bool supports;
1166 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1167 mBluetoothA2dp->supportsOffloadReconfiguration(&supports)));
1168 result->addInt(key, supports ? 1 : 0);
1169 }
1170 return OK;
1171}
1172
Mikhail Naganov27382bb2023-04-27 18:14:15 -07001173status_t DeviceHalAidl::filterAndUpdateBtA2dpParameters(AudioParameter &parameters) {
1174 TIME_CHECK();
1175 std::optional<bool> a2dpEnabled;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001176 std::optional<std::vector<VendorParameter>> reconfigureOffload;
Mikhail Naganov27382bb2023-04-27 18:14:15 -07001177 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1178 parameters, String8(AudioParameter::keyBtA2dpSuspended),
1179 [&a2dpEnabled](const String8& trueOrFalse) {
1180 if (trueOrFalse == AudioParameter::valueTrue) {
1181 a2dpEnabled = false; // 'suspended' == true
1182 return OK;
1183 } else if (trueOrFalse == AudioParameter::valueFalse) {
1184 a2dpEnabled = true; // 'suspended' == false
1185 return OK;
1186 }
1187 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1188 AudioParameter::keyBtA2dpSuspended, trueOrFalse.c_str());
1189 return BAD_VALUE;
1190 }));
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001191 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1192 parameters, String8(AudioParameter::keyReconfigA2dp),
1193 [&](const String8& value) -> status_t {
1194 if (mVendorExt != nullptr) {
1195 std::vector<VendorParameter> result;
1196 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1197 mVendorExt->parseBluetoothA2dpReconfigureOffload(
1198 std::string(value.c_str()), &result)));
1199 reconfigureOffload = std::move(result);
1200 } else {
1201 reconfigureOffload = std::vector<VendorParameter>();
1202 }
1203 return OK;
1204 }));
Mikhail Naganov27382bb2023-04-27 18:14:15 -07001205 if (mBluetoothA2dp != nullptr && a2dpEnabled.has_value()) {
1206 return statusTFromBinderStatus(mBluetoothA2dp->setEnabled(a2dpEnabled.value()));
1207 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001208 if (mBluetoothA2dp != nullptr && reconfigureOffload.has_value()) {
1209 return statusTFromBinderStatus(mBluetoothA2dp->reconfigureOffload(
1210 reconfigureOffload.value()));
1211 }
Mikhail Naganov27382bb2023-04-27 18:14:15 -07001212 return OK;
1213}
1214
1215status_t DeviceHalAidl::filterAndUpdateBtHfpParameters(AudioParameter &parameters) {
1216 TIME_CHECK();
1217 IBluetooth::HfpConfig hfpConfig;
1218 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1219 parameters, String8(AudioParameter::keyBtHfpEnable),
1220 [&hfpConfig](const String8& trueOrFalse) {
1221 if (trueOrFalse == AudioParameter::valueTrue) {
1222 hfpConfig.isEnabled = Boolean{ .value = true };
1223 return OK;
1224 } else if (trueOrFalse == AudioParameter::valueFalse) {
1225 hfpConfig.isEnabled = Boolean{ .value = false };
1226 return OK;
1227 }
1228 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1229 AudioParameter::keyBtHfpEnable, trueOrFalse.c_str());
1230 return BAD_VALUE;
1231 }));
1232 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1233 parameters, String8(AudioParameter::keyBtHfpSamplingRate),
1234 [&hfpConfig](int sampleRate) {
1235 return sampleRate > 0 ?
1236 hfpConfig.sampleRate = Int{ .value = sampleRate }, OK : BAD_VALUE;
1237 }));
1238 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1239 parameters, String8(AudioParameter::keyBtHfpVolume),
1240 [&hfpConfig](int volume0to15) {
1241 if (volume0to15 >= 0 && volume0to15 <= 15) {
1242 hfpConfig.volume = Float{ .value = volume0to15 / 15.0f };
1243 return OK;
1244 }
1245 return BAD_VALUE;
1246 }));
1247 if (mBluetooth != nullptr && hfpConfig != IBluetooth::HfpConfig{}) {
1248 IBluetooth::HfpConfig newHfpConfig;
1249 return statusTFromBinderStatus(mBluetooth->setHfpConfig(hfpConfig, &newHfpConfig));
1250 }
1251 return OK;
1252}
1253
1254status_t DeviceHalAidl::filterAndUpdateBtLeParameters(AudioParameter &parameters) {
1255 TIME_CHECK();
1256 std::optional<bool> leEnabled;
1257 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1258 parameters, String8(AudioParameter::keyBtLeSuspended),
1259 [&leEnabled](const String8& trueOrFalse) {
1260 if (trueOrFalse == AudioParameter::valueTrue) {
1261 leEnabled = false; // 'suspended' == true
1262 return OK;
1263 } else if (trueOrFalse == AudioParameter::valueFalse) {
1264 leEnabled = true; // 'suspended' == false
1265 return OK;
1266 }
1267 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1268 AudioParameter::keyBtLeSuspended, trueOrFalse.c_str());
1269 return BAD_VALUE;
1270 }));
1271 if (mBluetoothLe != nullptr && leEnabled.has_value()) {
1272 return statusTFromBinderStatus(mBluetoothLe->setEnabled(leEnabled.value()));
1273 }
1274 return OK;
1275}
1276
1277status_t DeviceHalAidl::filterAndUpdateBtScoParameters(AudioParameter &parameters) {
1278 TIME_CHECK();
1279 IBluetooth::ScoConfig scoConfig;
1280 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1281 parameters, String8(AudioParameter::keyBtSco),
1282 [&scoConfig](const String8& onOrOff) {
1283 if (onOrOff == AudioParameter::valueOn) {
1284 scoConfig.isEnabled = Boolean{ .value = true };
1285 return OK;
1286 } else if (onOrOff == AudioParameter::valueOff) {
1287 scoConfig.isEnabled = Boolean{ .value = false };
1288 return OK;
1289 }
1290 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1291 AudioParameter::keyBtSco, onOrOff.c_str());
1292 return BAD_VALUE;
1293 }));
1294 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1295 parameters, String8(AudioParameter::keyBtScoHeadsetName),
1296 [&scoConfig](const String8& name) {
1297 scoConfig.debugName = name;
1298 return OK;
1299 }));
1300 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1301 parameters, String8(AudioParameter::keyBtNrec),
1302 [&scoConfig](const String8& onOrOff) {
1303 if (onOrOff == AudioParameter::valueOn) {
1304 scoConfig.isNrecEnabled = Boolean{ .value = true };
1305 return OK;
1306 } else if (onOrOff == AudioParameter::valueOff) {
1307 scoConfig.isNrecEnabled = Boolean{ .value = false };
1308 return OK;
1309 }
1310 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1311 AudioParameter::keyBtNrec, onOrOff.c_str());
1312 return BAD_VALUE;
1313 }));
1314 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1315 parameters, String8(AudioParameter::keyBtScoWb),
1316 [&scoConfig](const String8& onOrOff) {
1317 if (onOrOff == AudioParameter::valueOn) {
1318 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO_WB;
1319 return OK;
1320 } else if (onOrOff == AudioParameter::valueOff) {
1321 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO;
1322 return OK;
1323 }
1324 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1325 AudioParameter::keyBtScoWb, onOrOff.c_str());
1326 return BAD_VALUE;
1327 }));
1328 if (mBluetooth != nullptr && scoConfig != IBluetooth::ScoConfig{}) {
1329 IBluetooth::ScoConfig newScoConfig;
1330 return statusTFromBinderStatus(mBluetooth->setScoConfig(scoConfig, &newScoConfig));
1331 }
1332 return OK;
1333}
1334
Mikhail Naganove92c34b2023-05-31 14:24:48 -07001335status_t DeviceHalAidl::filterAndUpdateScreenParameters(AudioParameter &parameters) {
1336 TIME_CHECK();
1337 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1338 parameters, String8(AudioParameter::keyScreenState),
1339 [&](const String8& onOrOff) -> status_t {
1340 std::optional<bool> isTurnedOn;
1341 if (onOrOff == AudioParameter::valueOn) {
1342 isTurnedOn = true;
1343 } else if (onOrOff == AudioParameter::valueOff) {
1344 isTurnedOn = false;
1345 }
1346 if (!isTurnedOn.has_value()) {
1347 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1348 AudioParameter::keyScreenState, onOrOff.c_str());
1349 return BAD_VALUE;
1350 }
1351 return statusTFromBinderStatus(
1352 mModule->updateScreenState(isTurnedOn.value()));
1353 }));
1354 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1355 parameters, String8(AudioParameter::keyScreenRotation),
1356 [&](int rotationDegrees) -> status_t {
1357 IModule::ScreenRotation rotation;
1358 switch (rotationDegrees) {
1359 case 0: rotation = IModule::ScreenRotation::DEG_0; break;
1360 case 90: rotation = IModule::ScreenRotation::DEG_90; break;
1361 case 180: rotation = IModule::ScreenRotation::DEG_180; break;
1362 case 270: rotation = IModule::ScreenRotation::DEG_270; break;
1363 default:
1364 ALOGE("setParameters: parameter key \"%s\" has invalid value %d",
1365 AudioParameter::keyScreenRotation, rotationDegrees);
1366 return BAD_VALUE;
1367 }
1368 return statusTFromBinderStatus(mModule->updateScreenRotation(rotation));
1369 }));
1370 return OK;
1371}
1372
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001373status_t DeviceHalAidl::findOrCreatePatch(
1374 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
1375 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
1376 requestedPatch.sourcePortConfigIds.end());
1377 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
1378 requestedPatch.sinkPortConfigIds.end());
1379 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
1380}
1381
1382status_t DeviceHalAidl::findOrCreatePatch(
1383 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
1384 AudioPatch* patch, bool* created) {
1385 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
1386 if (patchIt == mPatches.end()) {
1387 TIME_CHECK();
1388 AudioPatch requestedPatch, appliedPatch;
1389 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
1390 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
1391 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
1392 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
1393 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
1394 requestedPatch, &appliedPatch)));
1395 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
1396 *created = true;
1397 } else {
1398 *created = false;
1399 }
1400 *patch = patchIt->second;
1401 return OK;
1402}
1403
jiabin2248fa12023-04-27 22:04:16 +00001404status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device, const AudioConfig* config,
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001405 AudioPortConfig* portConfig, bool* created) {
1406 auto portConfigIt = findPortConfig(device);
1407 if (portConfigIt == mPortConfigs.end()) {
1408 auto portsIt = findPort(device);
1409 if (portsIt == mPorts.end()) {
1410 ALOGE("%s: device port for device %s is not found in the module %s",
1411 __func__, device.toString().c_str(), mInstance.c_str());
1412 return BAD_VALUE;
1413 }
1414 AudioPortConfig requestedPortConfig;
1415 requestedPortConfig.portId = portsIt->first;
jiabin2248fa12023-04-27 22:04:16 +00001416 if (config != nullptr) {
1417 setPortConfigFromConfig(&requestedPortConfig, *config);
1418 }
David Lia8f1e582023-03-30 21:08:06 +08001419 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1420 created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001421 } else {
1422 *created = false;
1423 }
1424 *portConfig = portConfigIt->second;
1425 return OK;
1426}
1427
1428status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001429 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001430 AudioSource source, const std::set<int32_t>& destinationPortIds,
1431 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001432 // These flags get removed one by one in this order when retrying port finding.
1433 static const std::vector<AudioInputFlags> kOptionalInputFlags{
1434 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001435 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001436 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001437 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
1438 AudioIoFlags matchFlags = flags.value();
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001439 auto portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001440 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
1441 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
1442 if (!isBitPositionFlagSet(
1443 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
1444 ++optionalInputFlagsIt;
1445 continue;
1446 }
1447 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
1448 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001449 portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001450 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
1451 "retried with flags %s", __func__, config.toString().c_str(),
1452 flags.value().toString().c_str(), mInstance.c_str(),
1453 matchFlags.toString().c_str());
1454 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001455 if (portsIt == mPorts.end()) {
1456 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001457 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001458 mInstance.c_str());
1459 return BAD_VALUE;
1460 }
1461 AudioPortConfig requestedPortConfig;
1462 requestedPortConfig.portId = portsIt->first;
1463 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001464 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001465 if (matchFlags.getTag() == AudioIoFlags::Tag::input
1466 && source != AudioSource::SYS_RESERVED_INVALID) {
1467 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
1468 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
1469 }
David Lia8f1e582023-03-30 21:08:06 +08001470 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1471 created));
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001472 } else if (!flags.has_value()) {
1473 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
1474 "and was not created as flags are not specified",
1475 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
1476 return BAD_VALUE;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001477 } else {
David Lia8f1e582023-03-30 21:08:06 +08001478 AudioPortConfig requestedPortConfig = portConfigIt->second;
1479 if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
1480 AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
1481 if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
1482 source != AudioSource::SYS_RESERVED_INVALID) {
1483 mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
1484 }
1485 }
1486
1487 if (requestedPortConfig != portConfigIt->second) {
1488 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1489 created));
1490 } else {
1491 *created = false;
1492 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001493 }
1494 *portConfig = portConfigIt->second;
1495 return OK;
1496}
1497
1498status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001499 const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
1500 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001501 using Tag = AudioPortExt::Tag;
1502 if (requestedPortConfig.ext.getTag() == Tag::mix) {
1503 if (const auto& p = requestedPortConfig;
1504 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001505 !p.format.has_value()) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001506 ALOGW("%s: provided mix port config is not fully specified: %s",
1507 __func__, p.toString().c_str());
1508 return BAD_VALUE;
1509 }
1510 AudioConfig config;
1511 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001512 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
1513 AudioPortMixExtUseCase::Tag::source ?
1514 requestedPortConfig.ext.get<Tag::mix>().usecase.
1515 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001516 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001517 requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
1518 portConfig, created);
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001519 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
1520 return findOrCreatePortConfig(
jiabin2248fa12023-04-27 22:04:16 +00001521 requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
1522 portConfig, created);
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001523 }
1524 ALOGW("%s: unsupported audio port config: %s",
1525 __func__, requestedPortConfig.toString().c_str());
1526 return BAD_VALUE;
1527}
1528
1529DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
1530 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
1531 return std::find_if(mPatches.begin(), mPatches.end(),
1532 [&](const auto& pair) {
1533 const auto& p = pair.second;
1534 std::set<int32_t> patchSrcs(
1535 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
1536 std::set<int32_t> patchSinks(
1537 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
1538 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
1539}
1540
1541DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001542 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1543 return mPorts.find(mDefaultInputPortId);
1544 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1545 return mPorts.find(mDefaultOutputPortId);
1546 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001547 return std::find_if(mPorts.begin(), mPorts.end(),
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001548 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001549}
1550
1551DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001552 const AudioConfig& config, const AudioIoFlags& flags,
1553 const std::set<int32_t>& destinationPortIds) {
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001554 auto belongsToProfile = [&config](const AudioProfile& prof) {
1555 return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
1556 (config.base.channelMask.getTag() == AudioChannelLayout::none ||
1557 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
1558 config.base.channelMask) != prof.channelMasks.end()) &&
1559 (config.base.sampleRate == 0 ||
1560 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
1561 config.base.sampleRate) != prof.sampleRates.end());
1562 };
jiabin2248fa12023-04-27 22:04:16 +00001563 static const std::vector<AudioOutputFlags> kOptionalOutputFlags{AudioOutputFlags::BIT_PERFECT};
1564 int optionalFlags = 0;
1565 auto flagMatches = [&flags, &optionalFlags](const AudioIoFlags& portFlags) {
1566 // Ports should be able to match if the optional flags are not requested.
1567 return portFlags == flags ||
1568 (portFlags.getTag() == AudioIoFlags::Tag::output &&
1569 AudioIoFlags::make<AudioIoFlags::Tag::output>(
1570 portFlags.get<AudioIoFlags::Tag::output>() &
1571 ~optionalFlags) == flags);
1572 };
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001573 auto matcher = [&](const auto& pair) {
1574 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001575 return p.ext.getTag() == AudioPortExt::Tag::mix &&
jiabin2248fa12023-04-27 22:04:16 +00001576 flagMatches(p.flags) &&
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001577 (destinationPortIds.empty() ||
1578 std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
1579 [&](const int32_t destId) { return mRoutingMatrix.count(
1580 std::make_pair(p.id, destId)) != 0; })) &&
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001581 (p.profiles.empty() ||
1582 std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
1583 p.profiles.end()); };
jiabin2248fa12023-04-27 22:04:16 +00001584 auto result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1585 if (result == mPorts.end() && flags.getTag() == AudioIoFlags::Tag::output) {
1586 auto optionalOutputFlagsIt = kOptionalOutputFlags.begin();
1587 while (result == mPorts.end() && optionalOutputFlagsIt != kOptionalOutputFlags.end()) {
1588 if (isBitPositionFlagSet(
1589 flags.get<AudioIoFlags::Tag::output>(), *optionalOutputFlagsIt)) {
1590 // If the flag is set by the request, it must be matched.
1591 ++optionalOutputFlagsIt;
1592 continue;
1593 }
1594 optionalFlags |= makeBitPositionFlagMask(*optionalOutputFlagsIt++);
1595 result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1596 ALOGI("%s: port for config %s, flags %s was not found in the module %s, "
1597 "retried with excluding optional flags %#x", __func__, config.toString().c_str(),
1598 flags.toString().c_str(), mInstance.c_str(), optionalFlags);
1599 }
1600 }
1601 return result;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001602}
1603
1604DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001605 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001606 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001607}
1608
1609DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001610 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001611 using Tag = AudioPortExt::Tag;
1612 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
1613 [&](const auto& pair) {
1614 const auto& p = pair.second;
1615 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
1616 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
1617 !p.format.has_value() || !p.flags.has_value(),
1618 "%s: stored mix port config is not fully specified: %s",
1619 __func__, p.toString().c_str());
1620 return p.ext.getTag() == Tag::mix &&
1621 isConfigEqualToPortConfig(config, p) &&
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001622 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001623 p.ext.template get<Tag::mix>().handle == ioHandle; });
1624}
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001625
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001626void DeviceHalAidl::resetPatch(int32_t patchId) {
1627 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1628 mPatches.erase(it);
1629 TIME_CHECK();
1630 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1631 ALOGE("%s: error while resetting patch %d: %s",
1632 __func__, patchId, status.getDescription().c_str());
1633 }
1634 return;
1635 }
1636 ALOGE("%s: patch id %d not found", __func__, patchId);
1637}
1638
1639void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1640 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1641 mPortConfigs.erase(it);
1642 TIME_CHECK();
1643 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1644 !status.isOk()) {
1645 ALOGE("%s: error while resetting port config %d: %s",
1646 __func__, portConfigId, status.getDescription().c_str());
1647 }
1648 return;
1649 }
1650 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1651}
1652
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001653void DeviceHalAidl::resetUnusedPatches() {
1654 // Since patches can be created independently of streams via 'createAudioPatch',
1655 // here we only clean up patches for released streams.
1656 for (auto it = mStreams.begin(); it != mStreams.end(); ) {
1657 if (auto streamSp = it->first.promote(); streamSp) {
1658 ++it;
1659 } else {
1660 resetPatch(it->second);
1661 it = mStreams.erase(it);
1662 }
1663 }
1664}
1665
1666void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
1667 resetUnusedPatches();
1668 resetUnusedPortConfigs();
1669}
1670
1671void DeviceHalAidl::resetUnusedPortConfigs() {
1672 // The assumption is that port configs are used to create patches
1673 // (or to open streams, but that involves creation of patches, too). Thus,
1674 // orphaned port configs can and should be reset.
1675 std::set<int32_t> portConfigIds;
1676 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
1677 std::inserter(portConfigIds, portConfigIds.end()),
1678 [](const auto& pcPair) { return pcPair.first; });
1679 for (const auto& p : mPatches) {
1680 for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
1681 for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
1682 }
jiabin2248fa12023-04-27 22:04:16 +00001683 for (int32_t id : mInitialPortConfigIds) {
1684 portConfigIds.erase(id);
1685 }
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001686 for (int32_t id : portConfigIds) resetPortConfig(id);
1687}
1688
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001689status_t DeviceHalAidl::updateRoutes() {
1690 TIME_CHECK();
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001691 RETURN_STATUS_IF_ERROR(
Mikhail Naganov2d814892023-04-24 13:06:04 -07001692 statusTFromBinderStatus(mModule->getAudioRoutes(&mRoutes)));
1693 ALOGW_IF(mRoutes.empty(), "%s: module %s returned an empty list of audio routes",
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001694 __func__, mInstance.c_str());
1695 mRoutingMatrix.clear();
Mikhail Naganov2d814892023-04-24 13:06:04 -07001696 for (const auto& r : mRoutes) {
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001697 for (auto portId : r.sourcePortIds) {
1698 mRoutingMatrix.emplace(r.sinkPortId, portId);
1699 mRoutingMatrix.emplace(portId, r.sinkPortId);
1700 }
1701 }
1702 return OK;
1703}
1704
Mikhail Naganovb0c55252023-02-08 16:59:41 -08001705void DeviceHalAidl::clearCallbacks(void* cookie) {
1706 std::lock_guard l(mLock);
1707 mCallbacks.erase(cookie);
1708}
1709
1710sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1711 return getCallbackImpl(cookie, &Callbacks::out);
1712}
1713
1714void DeviceHalAidl::setStreamOutCallback(
1715 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1716 setCallbackImpl(cookie, &Callbacks::out, cb);
1717}
1718
1719sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1720 void* cookie) {
1721 return getCallbackImpl(cookie, &Callbacks::event);
1722}
1723
1724void DeviceHalAidl::setStreamOutEventCallback(
1725 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1726 setCallbackImpl(cookie, &Callbacks::event, cb);
1727}
1728
1729sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1730 void* cookie) {
1731 return getCallbackImpl(cookie, &Callbacks::latency);
1732}
1733
1734void DeviceHalAidl::setStreamOutLatencyModeCallback(
1735 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1736 setCallbackImpl(cookie, &Callbacks::latency, cb);
1737}
1738
1739template<class C>
1740sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1741 std::lock_guard l(mLock);
1742 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1743 return ((it->second).*field).promote();
1744 }
1745 return nullptr;
1746}
1747template<class C>
1748void DeviceHalAidl::setCallbackImpl(
1749 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1750 std::lock_guard l(mLock);
1751 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1752 (it->second).*field = cb;
1753 }
1754}
1755
Mikhail Naganov31d46652023-01-10 18:29:25 +00001756} // namespace android