blob: 22bdc230601404ba706467f1d85c6de92818e958 [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"
35#include "StreamHalAidl.h"
36
Mikhail Naganovfab697c2023-01-11 19:33:13 +000037using aidl::android::aidl_utils::statusTFromBinderStatus;
Mikhail Naganovccc82112023-04-27 18:14:15 -070038using aidl::android::media::audio::common::Boolean;
Mikhail Naganove93a0862023-03-15 17:06:59 -070039using aidl::android::media::audio::common::AudioChannelLayout;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080040using aidl::android::media::audio::common::AudioConfig;
41using aidl::android::media::audio::common::AudioDevice;
David Li9cf5e622023-03-21 00:51:10 +080042using aidl::android::media::audio::common::AudioDeviceAddress;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080043using aidl::android::media::audio::common::AudioDeviceType;
Mikhail Naganove93a0862023-03-15 17:06:59 -070044using aidl::android::media::audio::common::AudioFormatType;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080045using aidl::android::media::audio::common::AudioInputFlags;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080046using aidl::android::media::audio::common::AudioIoFlags;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -080047using aidl::android::media::audio::common::AudioLatencyMode;
David Li9cf5e622023-03-21 00:51:10 +080048using aidl::android::media::audio::common::AudioMMapPolicy;
49using aidl::android::media::audio::common::AudioMMapPolicyInfo;
50using aidl::android::media::audio::common::AudioMMapPolicyType;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000051using aidl::android::media::audio::common::AudioMode;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080052using aidl::android::media::audio::common::AudioOutputFlags;
53using aidl::android::media::audio::common::AudioPort;
54using aidl::android::media::audio::common::AudioPortConfig;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080055using aidl::android::media::audio::common::AudioPortDeviceExt;
David Li9cf5e622023-03-21 00:51:10 +080056using aidl::android::media::audio::common::AudioPortExt;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -080057using aidl::android::media::audio::common::AudioPortMixExt;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -080058using aidl::android::media::audio::common::AudioPortMixExtUseCase;
Mikhail Naganove93a0862023-03-15 17:06:59 -070059using aidl::android::media::audio::common::AudioProfile;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080060using aidl::android::media::audio::common::AudioSource;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000061using aidl::android::media::audio::common::Float;
David Li9cf5e622023-03-21 00:51:10 +080062using aidl::android::media::audio::common::Int;
63using aidl::android::media::audio::common::MicrophoneDynamicInfo;
64using aidl::android::media::audio::common::MicrophoneInfo;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -070065using aidl::android::media::audio::IHalAdapterVendorExtension;
Mikhail Naganov6352e822023-03-09 18:22:36 -080066using aidl::android::hardware::audio::common::getFrameSizeInBytes;
67using aidl::android::hardware::audio::common::isBitPositionFlagSet;
Mikhail Naganove93a0862023-03-15 17:06:59 -070068using aidl::android::hardware::audio::common::isDefaultAudioFormat;
Mikhail Naganov6352e822023-03-09 18:22:36 -080069using aidl::android::hardware::audio::common::makeBitPositionFlagMask;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080070using aidl::android::hardware::audio::common::RecordTrackMetadata;
71using aidl::android::hardware::audio::core::AudioPatch;
Mikhail Naganov289468a2023-03-29 10:06:15 -070072using aidl::android::hardware::audio::core::AudioRoute;
Mikhail Naganovccc82112023-04-27 18:14:15 -070073using aidl::android::hardware::audio::core::IBluetooth;
74using aidl::android::hardware::audio::core::IBluetoothA2dp;
75using aidl::android::hardware::audio::core::IBluetoothLe;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000076using aidl::android::hardware::audio::core::IModule;
77using aidl::android::hardware::audio::core::ITelephony;
Mikhail Naganove93a0862023-03-15 17:06:59 -070078using aidl::android::hardware::audio::core::ModuleDebug;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000079using aidl::android::hardware::audio::core::StreamDescriptor;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -070080using aidl::android::hardware::audio::core::VendorParameter;
Mikhail Naganov31d46652023-01-10 18:29:25 +000081
82namespace android {
83
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080084namespace {
85
86bool isConfigEqualToPortConfig(const AudioConfig& config, const AudioPortConfig& portConfig) {
87 return portConfig.sampleRate.value().value == config.base.sampleRate &&
88 portConfig.channelMask.value() == config.base.channelMask &&
89 portConfig.format.value() == config.base.format;
90}
91
92void setConfigFromPortConfig(AudioConfig* config, const AudioPortConfig& portConfig) {
93 config->base.sampleRate = portConfig.sampleRate.value().value;
94 config->base.channelMask = portConfig.channelMask.value();
95 config->base.format = portConfig.format.value();
96}
97
98void setPortConfigFromConfig(AudioPortConfig* portConfig, const AudioConfig& config) {
99 portConfig->sampleRate = Int{ .value = config.base.sampleRate };
100 portConfig->channelMask = config.base.channelMask;
101 portConfig->format = config.base.format;
102}
103
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700104// Note: these converters are for types defined in different AIDL files. Although these
105// AIDL files are copies of each other, however formally these are different types
106// thus we don't use a conversion via a parcelable.
107ConversionResult<media::AudioRoute> ndk2cpp_AudioRoute(const AudioRoute& ndk) {
108 media::AudioRoute cpp;
109 cpp.sourcePortIds.insert(
110 cpp.sourcePortIds.end(), ndk.sourcePortIds.begin(), ndk.sourcePortIds.end());
111 cpp.sinkPortId = ndk.sinkPortId;
112 cpp.isExclusive = ndk.isExclusive;
David Li9cf5e622023-03-21 00:51:10 +0800113 return cpp;
114}
115
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700116template<typename T>
117std::shared_ptr<T> retrieveSubInterface(const std::shared_ptr<IModule>& module,
118 ::ndk::ScopedAStatus (IModule::*getT)(std::shared_ptr<T>*)) {
119 if (module != nullptr) {
120 std::shared_ptr<T> instance;
121 if (auto status = (module.get()->*getT)(&instance); status.isOk()) {
122 return instance;
123 }
124 }
125 return nullptr;
126}
127
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800128} // namespace
129
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700130DeviceHalAidl::DeviceHalAidl(const std::string& instance, const std::shared_ptr<IModule>& module,
131 const std::shared_ptr<IHalAdapterVendorExtension>& vext)
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700132 : ConversionHelperAidl("DeviceHalAidl"),
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700133 mInstance(instance), mModule(module), mVendorExt(vext),
Mikhail Naganovccc82112023-04-27 18:14:15 -0700134 mTelephony(retrieveSubInterface<ITelephony>(module, &IModule::getTelephony)),
135 mBluetooth(retrieveSubInterface<IBluetooth>(module, &IModule::getBluetooth)),
136 mBluetoothA2dp(retrieveSubInterface<IBluetoothA2dp>(module, &IModule::getBluetoothA2dp)),
137 mBluetoothLe(retrieveSubInterface<IBluetoothLe>(module, &IModule::getBluetoothLe)) {
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700138}
139
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700140status_t DeviceHalAidl::getAudioPorts(std::vector<media::audio::common::AudioPort> *ports) {
Mikhail Naganov9e459d72023-05-05 17:36:39 -0700141 return ::aidl::android::convertContainer(mPorts, ports,
142 [](const Ports::value_type& pair) { return ndk2cpp_AudioPort(pair.second); });
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700143}
144
145status_t DeviceHalAidl::getAudioRoutes(std::vector<media::AudioRoute> *routes) {
146 *routes = VALUE_OR_RETURN_STATUS(
147 ::aidl::android::convertContainer<std::vector<media::AudioRoute>>(
148 mRoutes, ndk2cpp_AudioRoute));
149 return OK;
150}
151
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700152status_t DeviceHalAidl::getSupportedModes(std::vector<media::audio::common::AudioMode> *modes) {
153 TIME_CHECK();
154 if (modes == nullptr) {
155 return BAD_VALUE;
156 }
157 if (mModule == nullptr) return NO_INIT;
158 if (mTelephony == nullptr) return INVALID_OPERATION;
159 std::vector<AudioMode> aidlModes;
160 RETURN_STATUS_IF_ERROR(
161 statusTFromBinderStatus(mTelephony->getSupportedAudioModes(&aidlModes)));
162 *modes = VALUE_OR_RETURN_STATUS(
163 ::aidl::android::convertContainer<std::vector<media::audio::common::AudioMode>>(
164 aidlModes, ndk2cpp_AudioMode));
165 return OK;
166}
167
Mikhail Naganov31d46652023-01-10 18:29:25 +0000168status_t DeviceHalAidl::getSupportedDevices(uint32_t*) {
169 // Obsolete.
170 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +0000171}
172
173status_t DeviceHalAidl::initCheck() {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800174 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000175 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800176 std::vector<AudioPort> ports;
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700177 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800178 ALOGW_IF(ports.empty(), "%s: module %s returned an empty list of audio ports",
179 __func__, mInstance.c_str());
180 std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()),
181 [](const auto& p) { return std::make_pair(p.id, p); });
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800182 mDefaultInputPortId = mDefaultOutputPortId = -1;
183 const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
184 for (const auto& pair : mPorts) {
185 const auto& p = pair.second;
186 if (p.ext.getTag() == AudioPortExt::Tag::device &&
187 (p.ext.get<AudioPortExt::Tag::device>().flags & defaultDeviceFlag) != 0) {
188 if (p.flags.getTag() == AudioIoFlags::Tag::input) {
189 mDefaultInputPortId = p.id;
190 } else if (p.flags.getTag() == AudioIoFlags::Tag::output) {
191 mDefaultOutputPortId = p.id;
192 }
193 }
194 }
195 ALOGI("%s: module %s default port ids: input %d, output %d",
196 __func__, mInstance.c_str(), mDefaultInputPortId, mDefaultOutputPortId);
Mikhail Naganov289468a2023-03-29 10:06:15 -0700197 RETURN_STATUS_IF_ERROR(updateRoutes());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800198 std::vector<AudioPortConfig> portConfigs;
199 RETURN_STATUS_IF_ERROR(
200 statusTFromBinderStatus(mModule->getAudioPortConfigs(&portConfigs))); // OK if empty
201 std::transform(portConfigs.begin(), portConfigs.end(),
202 std::inserter(mPortConfigs, mPortConfigs.end()),
203 [](const auto& p) { return std::make_pair(p.id, p); });
jiabin9c07faf2023-04-26 22:00:44 +0000204 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
205 std::inserter(mInitialPortConfigIds, mInitialPortConfigIds.end()),
206 [](const auto& pcPair) { return pcPair.first; });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800207 std::vector<AudioPatch> patches;
208 RETURN_STATUS_IF_ERROR(
209 statusTFromBinderStatus(mModule->getAudioPatches(&patches))); // OK if empty
210 std::transform(patches.begin(), patches.end(),
211 std::inserter(mPatches, mPatches.end()),
212 [](const auto& p) { return std::make_pair(p.id, p); });
Shunkai Yao51202502022-12-12 06:11:46 +0000213 return OK;
214}
215
216status_t DeviceHalAidl::setVoiceVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000217 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000218 if (!mModule) return NO_INIT;
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700219 if (mTelephony == nullptr) return INVALID_OPERATION;
220 ITelephony::TelecomConfig inConfig{ .voiceVolume = Float{volume} }, outConfig;
221 RETURN_STATUS_IF_ERROR(
222 statusTFromBinderStatus(mTelephony->setTelecomConfig(inConfig, &outConfig)));
223 ALOGW_IF(outConfig.voiceVolume.has_value() && volume != outConfig.voiceVolume.value().value,
224 "%s: the resulting voice volume %f is not the same as requested %f",
225 __func__, outConfig.voiceVolume.value().value, volume);
226 return OK;
Shunkai Yao51202502022-12-12 06:11:46 +0000227}
228
229status_t DeviceHalAidl::setMasterVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000230 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000231 if (!mModule) return NO_INIT;
232 return statusTFromBinderStatus(mModule->setMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000233}
234
235status_t DeviceHalAidl::getMasterVolume(float *volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000236 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000237 if (!mModule) return NO_INIT;
238 return statusTFromBinderStatus(mModule->getMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000239}
240
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000241status_t DeviceHalAidl::setMode(audio_mode_t mode) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000242 TIME_CHECK();
243 if (!mModule) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000244 AudioMode audioMode = VALUE_OR_FATAL(::aidl::android::legacy2aidl_audio_mode_t_AudioMode(mode));
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700245 if (mTelephony != nullptr) {
246 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mTelephony->switchAudioMode(audioMode)));
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000247 }
248 return statusTFromBinderStatus(mModule->updateAudioMode(audioMode));
Shunkai Yao51202502022-12-12 06:11:46 +0000249}
250
251status_t DeviceHalAidl::setMicMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000252 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000253 if (!mModule) return NO_INIT;
254 return statusTFromBinderStatus(mModule->setMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000255}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000256
Shunkai Yao51202502022-12-12 06:11:46 +0000257status_t DeviceHalAidl::getMicMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000258 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000259 if (!mModule) return NO_INIT;
260 return statusTFromBinderStatus(mModule->getMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000261}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000262
Shunkai Yao51202502022-12-12 06:11:46 +0000263status_t DeviceHalAidl::setMasterMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000264 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000265 if (!mModule) return NO_INIT;
266 return statusTFromBinderStatus(mModule->setMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000267}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000268
Shunkai Yao51202502022-12-12 06:11:46 +0000269status_t DeviceHalAidl::getMasterMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000270 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000271 if (!mModule) return NO_INIT;
272 return statusTFromBinderStatus(mModule->getMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000273}
274
Mikhail Naganovccc82112023-04-27 18:14:15 -0700275status_t DeviceHalAidl::setParameters(const String8& kvPairs) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000276 if (!mModule) return NO_INIT;
Mikhail Naganovccc82112023-04-27 18:14:15 -0700277 AudioParameter parameters(kvPairs);
278 ALOGD("%s: parameters: \"%s\"", __func__, parameters.toString().c_str());
279
280 if (status_t status = filterAndUpdateBtA2dpParameters(parameters); status != OK) {
281 ALOGW("%s: filtering or updating BT A2DP parameters failed: %d", __func__, status);
282 }
283 if (status_t status = filterAndUpdateBtHfpParameters(parameters); status != OK) {
284 ALOGW("%s: filtering or updating BT HFP parameters failed: %d", __func__, status);
285 }
286 if (status_t status = filterAndUpdateBtLeParameters(parameters); status != OK) {
287 ALOGW("%s: filtering or updating BT LE parameters failed: %d", __func__, status);
288 }
289 if (status_t status = filterAndUpdateBtScoParameters(parameters); status != OK) {
290 ALOGW("%s: filtering or updating BT SCO parameters failed: %d", __func__, status);
291 }
Mikhail Naganove92c34b2023-05-31 14:24:48 -0700292 if (status_t status = filterAndUpdateScreenParameters(parameters); status != OK) {
293 ALOGW("%s: filtering or updating screen parameters failed: %d", __func__, status);
294 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700295 return parseAndSetVendorParameters(mVendorExt, mModule, parameters);
Shunkai Yao51202502022-12-12 06:11:46 +0000296}
297
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700298status_t DeviceHalAidl::getParameters(const String8& keys, String8 *values) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000299 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000300 if (!mModule) return NO_INIT;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700301 if (values == nullptr) {
302 return BAD_VALUE;
303 }
304 AudioParameter parameterKeys(keys), result;
305 if (status_t status = filterAndRetrieveBtA2dpParameters(parameterKeys, &result); status != OK) {
306 ALOGW("%s: filtering or retrieving BT A2DP parameters failed: %d", __func__, status);
307 }
308 *values = result.toString();
309 return parseAndGetVendorParameters(mVendorExt, mModule, parameterKeys, values);
Shunkai Yao51202502022-12-12 06:11:46 +0000310}
311
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800312namespace {
313
314class Cleanup {
315 public:
316 typedef void (DeviceHalAidl::*Cleaner)(int32_t);
317
318 Cleanup(DeviceHalAidl* device, Cleaner cleaner, int32_t id) :
319 mDevice(device), mCleaner(cleaner), mId(id) {}
320 ~Cleanup() { clean(); }
321 void clean() {
322 if (mDevice != nullptr) (mDevice->*mCleaner)(mId);
323 disarm();
324 }
325 void disarm() { mDevice = nullptr; }
326
327 private:
328 DeviceHalAidl* mDevice;
329 const Cleaner mCleaner;
330 const int32_t mId;
331};
332
333} // namespace
334
335// Since the order of container elements destruction is unspecified,
336// ensure that cleanups are performed from the most recent one and upwards.
337// This is the same as if there were individual Cleanup instances on the stack,
338// however the bonus is that we can disarm all of them with just one statement.
339class DeviceHalAidl::Cleanups : public std::forward_list<Cleanup> {
340 public:
341 ~Cleanups() { for (auto& c : *this) c.clean(); }
342 void disarmAll() { for (auto& c : *this) c.disarm(); }
343};
344
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800345status_t DeviceHalAidl::getInputBufferSize(const struct audio_config* config, size_t* size) {
346 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
347 if (size == nullptr) return BAD_VALUE;
348 TIME_CHECK();
349 if (!mModule) return NO_INIT;
350 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
351 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
352 AudioDevice aidlDevice;
353 aidlDevice.type.type = AudioDeviceType::IN_DEFAULT;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800354 AudioSource aidlSource = AudioSource::DEFAULT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800355 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
356 AudioPortConfig mixPortConfig;
357 Cleanups cleanups;
358 audio_config writableConfig = *config;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700359 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800360 RETURN_STATUS_IF_ERROR(prepareToOpenStream(0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700361 &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800362 *size = aidlConfig.frameCount *
363 getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
364 // Do not disarm cleanups to release temporary port configs.
365 return OK;
366}
367
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800368status_t DeviceHalAidl::prepareToOpenStream(
369 int32_t aidlHandle, const AudioDevice& aidlDevice, const AudioIoFlags& aidlFlags,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800370 AudioSource aidlSource, struct audio_config* config,
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800371 Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700372 AudioPatch* aidlPatch) {
373 ALOGD("%p %s::%s: handle %d, device %s, flags %s, source %s, config %s, mix port config %s",
374 this, getClassName().c_str(), __func__, aidlHandle, aidlDevice.toString().c_str(),
375 aidlFlags.toString().c_str(), toString(aidlSource).c_str(),
376 aidlConfig->toString().c_str(), mixPortConfig->toString().c_str());
jiabin9c07faf2023-04-26 22:00:44 +0000377 resetUnusedPatchesAndPortConfigs();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800378 const bool isInput = aidlFlags.getTag() == AudioIoFlags::Tag::input;
379 // Find / create AudioPortConfigs for the device port and the mix port,
380 // then find / create a patch between them, and open a stream on the mix port.
381 AudioPortConfig devicePortConfig;
382 bool created = false;
jiabin9c07faf2023-04-26 22:00:44 +0000383 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, aidlConfig,
384 &devicePortConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800385 if (created) {
386 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
387 }
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800388 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*aidlConfig, aidlFlags, aidlHandle, aidlSource,
Mikhail Naganov289468a2023-03-29 10:06:15 -0700389 std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800390 if (created) {
391 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
392 }
393 setConfigFromPortConfig(aidlConfig, *mixPortConfig);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800394 if (isInput) {
395 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700396 {devicePortConfig.id}, {mixPortConfig->id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800397 } else {
398 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700399 {mixPortConfig->id}, {devicePortConfig.id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800400 }
401 if (created) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700402 cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, aidlPatch->id);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800403 }
404 if (aidlConfig->frameCount <= 0) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700405 aidlConfig->frameCount = aidlPatch->minimumStreamBufferSizeFrames;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800406 }
407 *config = VALUE_OR_RETURN_STATUS(
408 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(*aidlConfig, isInput));
409 return OK;
410}
411
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800412namespace {
413
414class StreamCallbackBase {
415 protected:
416 explicit StreamCallbackBase(const sp<CallbackBroker>& broker) : mBroker(broker) {}
417 public:
418 void* getCookie() const { return mCookie; }
419 void setCookie(void* cookie) { mCookie = cookie; }
420 sp<CallbackBroker> getBroker() const {
421 if (void* cookie = mCookie; cookie != nullptr) return mBroker.promote();
422 return nullptr;
423 }
424 private:
425 const wp<CallbackBroker> mBroker;
426 std::atomic<void*> mCookie;
427};
428
429template<class C>
430class StreamCallbackBaseHelper {
431 protected:
432 explicit StreamCallbackBaseHelper(const StreamCallbackBase& base) : mBase(base) {}
433 sp<C> getCb(const sp<CallbackBroker>& broker, void* cookie);
434 using CbRef = const sp<C>&;
435 ndk::ScopedAStatus runCb(const std::function<void(CbRef cb)>& f) {
436 if (auto cb = getCb(mBase.getBroker(), mBase.getCookie()); cb != nullptr) f(cb);
437 return ndk::ScopedAStatus::ok();
438 }
439 private:
440 const StreamCallbackBase& mBase;
441};
442
443template<>
444sp<StreamOutHalInterfaceCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>::getCb(
445 const sp<CallbackBroker>& broker, void* cookie) {
446 if (broker != nullptr) return broker->getStreamOutCallback(cookie);
447 return nullptr;
448}
449
450template<>
451sp<StreamOutHalInterfaceEventCallback>
452StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::getCb(
453 const sp<CallbackBroker>& broker, void* cookie) {
454 if (broker != nullptr) return broker->getStreamOutEventCallback(cookie);
455 return nullptr;
456}
457
458template<>
459sp<StreamOutHalInterfaceLatencyModeCallback>
460StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::getCb(
461 const sp<CallbackBroker>& broker, void* cookie) {
462 if (broker != nullptr) return broker->getStreamOutLatencyModeCallback(cookie);
463 return nullptr;
464}
465
466/*
467Note on the callback ownership.
468
469In the Binder ownership model, the server implementation is kept alive
470as long as there is any client (proxy object) alive. This is done by
471incrementing the refcount of the server-side object by the Binder framework.
472When it detects that the last client is gone, it decrements the refcount back.
473
474Thus, it is not needed to keep any references to StreamCallback on our
475side (after we have sent an instance to the client), because we are
476the server-side. The callback object will be kept alive as long as the HAL server
477holds a strong ref to IStreamCallback proxy.
478*/
479
480class OutputStreamCallbackAidl : public StreamCallbackBase,
481 public StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>,
482 public ::aidl::android::hardware::audio::core::BnStreamCallback {
483 public:
484 explicit OutputStreamCallbackAidl(const sp<CallbackBroker>& broker)
485 : StreamCallbackBase(broker),
486 StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>(
487 *static_cast<StreamCallbackBase*>(this)) {}
488 ndk::ScopedAStatus onTransferReady() override {
489 return runCb([](CbRef cb) { cb->onWriteReady(); });
490 }
491 ndk::ScopedAStatus onError() override {
492 return runCb([](CbRef cb) { cb->onError(); });
493 }
494 ndk::ScopedAStatus onDrainReady() override {
495 return runCb([](CbRef cb) { cb->onDrainReady(); });
496 }
497};
498
499class OutputStreamEventCallbackAidl :
500 public StreamCallbackBase,
501 public StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>,
502 public StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>,
503 public ::aidl::android::hardware::audio::core::BnStreamOutEventCallback {
504 public:
505 explicit OutputStreamEventCallbackAidl(const sp<CallbackBroker>& broker)
506 : StreamCallbackBase(broker),
507 StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>(
508 *static_cast<StreamCallbackBase*>(this)),
509 StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>(
510 *static_cast<StreamCallbackBase*>(this)) {}
511 ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& in_audioMetadata) override {
512 std::basic_string<uint8_t> halMetadata(in_audioMetadata.begin(), in_audioMetadata.end());
513 return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb(
514 [&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); });
515 }
516 ndk::ScopedAStatus onRecommendedLatencyModeChanged(
517 const std::vector<AudioLatencyMode>& in_modes) override {
518 auto halModes = VALUE_OR_FATAL(
519 ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
520 in_modes,
521 ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
522 return StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::runCb(
523 [&halModes](auto cb) { cb->onRecommendedLatencyModeChanged(halModes); });
524 }
525};
526
527} // namespace
528
Mikhail Naganov31d46652023-01-10 18:29:25 +0000529status_t DeviceHalAidl::openOutputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800530 audio_io_handle_t handle, audio_devices_t devices,
531 audio_output_flags_t flags, struct audio_config* config,
532 const char* address,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000533 sp<StreamOutHalInterface>* outStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800534 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000535 if (!outStream || !config) {
536 return BAD_VALUE;
537 }
538 TIME_CHECK();
539 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800540 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
541 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
542 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
543 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, false /*isInput*/));
544 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
545 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
546 int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
547 ::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
548 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
549 AudioPortConfig mixPortConfig;
550 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700551 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800552 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
553 AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700554 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800555 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
556 args.portConfigId = mixPortConfig.id;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800557 const bool isOffload = isBitPositionFlagSet(
558 aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD);
559 std::shared_ptr<OutputStreamCallbackAidl> streamCb;
560 if (isOffload) {
561 streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
562 }
563 auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
564 if (isOffload) {
565 args.offloadInfo = aidlConfig.offloadInfo;
566 args.callback = streamCb;
567 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800568 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800569 args.eventCallback = eventCb;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800570 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
571 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800572 StreamContextAidl context(ret.desc, isOffload);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800573 if (!context.isValid()) {
574 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
575 __func__, ret.desc.toString().c_str());
576 return NO_INIT;
577 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700578 *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700579 std::move(ret.stream), mVendorExt, this /*callbackBroker*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700580 mStreams.insert(std::pair(*outStream, aidlPatch.id));
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800581 void* cbCookie = (*outStream).get();
582 {
583 std::lock_guard l(mLock);
584 mCallbacks.emplace(cbCookie, Callbacks{});
585 }
586 if (streamCb) streamCb->setCookie(cbCookie);
587 eventCb->setCookie(cbCookie);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800588 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000589 return OK;
590}
591
Mikhail Naganov31d46652023-01-10 18:29:25 +0000592status_t DeviceHalAidl::openInputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800593 audio_io_handle_t handle, audio_devices_t devices,
594 struct audio_config* config, audio_input_flags_t flags,
595 const char* address, audio_source_t source,
596 audio_devices_t outputDevice, const char* outputDeviceAddress,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000597 sp<StreamInHalInterface>* inStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800598 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000599 if (!inStream || !config) {
600 return BAD_VALUE;
601 }
602 TIME_CHECK();
603 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800604 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
605 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
606 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
607 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
608 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
609 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
610 int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
611 ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
612 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
613 AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
614 ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
615 AudioPortConfig mixPortConfig;
616 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700617 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800618 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700619 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800620 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
621 args.portConfigId = mixPortConfig.id;
622 RecordTrackMetadata aidlTrackMetadata{
623 .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
624 if (outputDevice != AUDIO_DEVICE_NONE) {
625 aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
626 ::aidl::android::legacy2aidl_audio_device_AudioDevice(
627 outputDevice, outputDeviceAddress));
628 }
629 args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
630 args.bufferSizeFrames = aidlConfig.frameCount;
631 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
632 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800633 StreamContextAidl context(ret.desc, false /*isAsynchronous*/);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800634 if (!context.isValid()) {
635 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
636 __func__, ret.desc.toString().c_str());
637 return NO_INIT;
638 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700639 *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700640 std::move(ret.stream), mVendorExt, this /*micInfoProvider*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700641 mStreams.insert(std::pair(*inStream, aidlPatch.id));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800642 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000643 return OK;
644}
645
646status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
647 *supportsPatches = true;
648 return OK;
649}
650
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800651status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
652 const struct audio_port_config* sources,
653 unsigned int num_sinks,
654 const struct audio_port_config* sinks,
655 audio_patch_handle_t* patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800656 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000657 TIME_CHECK();
658 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800659 if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
660 sources == nullptr || sinks == nullptr || patch == nullptr) {
661 return BAD_VALUE;
662 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800663 // When the patch handle (*patch) is AUDIO_PATCH_HANDLE_NONE, it means
664 // the framework wants to create a new patch. The handle has to be generated
665 // by the HAL. Since handles generated this way can only be unique within
666 // a HAL module, the framework generates a globally unique handle, and maps
667 // it on the <HAL module, patch handle> pair.
668 // When the patch handle is set, it meant the framework intends to update
669 // an existing patch.
670 //
671 // This behavior corresponds to HAL module behavior, with the only difference
672 // that the HAL module uses `int32_t` for patch IDs. The following assert ensures
673 // that both the framework and the HAL use the same value for "no ID":
674 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
675 int32_t halPatchId = static_cast<int32_t>(*patch);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800676
677 // Upon conversion, mix port configs contain audio configuration, while
678 // device port configs contain device address. This data is used to find
679 // or create HAL configs.
680 std::vector<AudioPortConfig> aidlSources, aidlSinks;
681 for (unsigned int i = 0; i < num_sources; ++i) {
682 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
683 sources[i].role, sources[i].type)) ==
684 ::aidl::android::AudioPortDirection::INPUT;
685 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
686 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
687 sources[i], isInput, 0)));
688 }
689 for (unsigned int i = 0; i < num_sinks; ++i) {
690 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
691 sinks[i].role, sinks[i].type)) ==
692 ::aidl::android::AudioPortDirection::INPUT;
693 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
694 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
695 sinks[i], isInput, 0)));
696 }
697 Cleanups cleanups;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800698 auto existingPatchIt = halPatchId != 0 ? mPatches.find(halPatchId): mPatches.end();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800699 AudioPatch aidlPatch;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800700 if (existingPatchIt != mPatches.end()) {
701 aidlPatch = existingPatchIt->second;
702 aidlPatch.sourcePortConfigIds.clear();
703 aidlPatch.sinkPortConfigIds.clear();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800704 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800705 ALOGD("%s: sources: %s, sinks: %s",
706 __func__, ::android::internal::ToString(aidlSources).c_str(),
707 ::android::internal::ToString(aidlSinks).c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800708 auto fillPortConfigs = [&](
Mikhail Naganov289468a2023-03-29 10:06:15 -0700709 const std::vector<AudioPortConfig>& configs,
710 const std::set<int32_t>& destinationPortIds,
711 std::vector<int32_t>* ids, std::set<int32_t>* portIds) -> status_t {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800712 for (const auto& s : configs) {
713 AudioPortConfig portConfig;
714 bool created = false;
Mikhail Naganov289468a2023-03-29 10:06:15 -0700715 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
716 s, destinationPortIds, &portConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800717 if (created) {
718 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, portConfig.id);
719 }
720 ids->push_back(portConfig.id);
Mikhail Naganov289468a2023-03-29 10:06:15 -0700721 if (portIds != nullptr) {
722 portIds->insert(portConfig.portId);
723 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800724 }
725 return OK;
726 };
Mikhail Naganov289468a2023-03-29 10:06:15 -0700727 // When looking up port configs, the destinationPortId is only used for mix ports.
728 // Thus, we process device port configs first, and look up the destination port ID from them.
729 bool sourceIsDevice = std::any_of(aidlSources.begin(), aidlSources.end(),
730 [](const auto& config) { return config.ext.getTag() == AudioPortExt::device; });
731 const std::vector<AudioPortConfig>& devicePortConfigs =
732 sourceIsDevice ? aidlSources : aidlSinks;
733 std::vector<int32_t>* devicePortConfigIds =
734 sourceIsDevice ? &aidlPatch.sourcePortConfigIds : &aidlPatch.sinkPortConfigIds;
735 const std::vector<AudioPortConfig>& mixPortConfigs =
736 sourceIsDevice ? aidlSinks : aidlSources;
737 std::vector<int32_t>* mixPortConfigIds =
738 sourceIsDevice ? &aidlPatch.sinkPortConfigIds : &aidlPatch.sourcePortConfigIds;
739 std::set<int32_t> devicePortIds;
740 RETURN_STATUS_IF_ERROR(fillPortConfigs(
741 devicePortConfigs, std::set<int32_t>(), devicePortConfigIds, &devicePortIds));
742 RETURN_STATUS_IF_ERROR(fillPortConfigs(
743 mixPortConfigs, devicePortIds, mixPortConfigIds, nullptr));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800744 if (existingPatchIt != mPatches.end()) {
745 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
746 mModule->setAudioPatch(aidlPatch, &aidlPatch)));
747 existingPatchIt->second = aidlPatch;
748 } else {
749 bool created = false;
750 RETURN_STATUS_IF_ERROR(findOrCreatePatch(aidlPatch, &aidlPatch, &created));
751 // Since no cleanup of the patch is needed, 'created' is ignored.
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800752 halPatchId = aidlPatch.id;
753 *patch = static_cast<audio_patch_handle_t>(halPatchId);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800754 }
755 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000756 return OK;
757}
758
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800759status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800760 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000761 TIME_CHECK();
762 if (!mModule) return NO_INIT;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800763 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
764 if (patch == AUDIO_PATCH_HANDLE_NONE) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800765 return BAD_VALUE;
766 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800767 int32_t halPatchId = static_cast<int32_t>(patch);
768 auto patchIt = mPatches.find(halPatchId);
769 if (patchIt == mPatches.end()) {
770 ALOGE("%s: patch with id %d not found", __func__, halPatchId);
771 return BAD_VALUE;
772 }
773 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->resetAudioPatch(halPatchId)));
774 mPatches.erase(patchIt);
Shunkai Yao51202502022-12-12 06:11:46 +0000775 return OK;
776}
777
Mikhail Naganove93a0862023-03-15 17:06:59 -0700778status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
779 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000780 TIME_CHECK();
781 if (!mModule) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700782 if (port == nullptr) {
783 return BAD_VALUE;
784 }
785 audio_port_v7 portV7;
786 audio_populate_audio_port_v7(port, &portV7);
787 RETURN_STATUS_IF_ERROR(getAudioPort(&portV7));
788 return audio_populate_audio_port(&portV7, port) ? OK : BAD_VALUE;
789}
790
791status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
792 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
793 TIME_CHECK();
794 if (!mModule) return NO_INIT;
795 if (port == nullptr) {
796 return BAD_VALUE;
797 }
798 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
799 ::aidl::android::AudioPortDirection::INPUT;
800 auto aidlPort = VALUE_OR_RETURN_STATUS(
801 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
802 if (aidlPort.ext.getTag() != AudioPortExt::device) {
803 ALOGE("%s: provided port is not a device port (module %s): %s",
804 __func__, mInstance.c_str(), aidlPort.toString().c_str());
805 return BAD_VALUE;
806 }
807 const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
808 // It seems that we don't have to call HAL since all valid ports have been added either
809 // during initialization, or while handling connection of an external device.
810 auto portsIt = findPort(matchDevice);
811 if (portsIt == mPorts.end()) {
812 ALOGE("%s: device port for device %s is not found in the module %s",
813 __func__, matchDevice.toString().c_str(), mInstance.c_str());
814 return BAD_VALUE;
815 }
816 const int32_t fwkId = aidlPort.id;
817 aidlPort = portsIt->second;
818 aidlPort.id = fwkId;
819 *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
820 aidlPort, isInput));
821 return OK;
822}
823
824status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
825 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
826 TIME_CHECK();
827 if (!mModule) return NO_INIT;
828 if (config == nullptr) {
829 return BAD_VALUE;
830 }
831 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
832 config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
833 AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
834 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
835 *config, isInput, 0 /*portId*/));
836 AudioPortConfig portConfig;
837 bool created = false;
Mikhail Naganov289468a2023-03-29 10:06:15 -0700838 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
839 requestedPortConfig, std::set<int32_t>(), &portConfig, &created));
Shunkai Yao51202502022-12-12 06:11:46 +0000840 return OK;
841}
842
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800843MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
844 if (mMicrophones.status == Microphones::Status::UNKNOWN) {
845 TIME_CHECK();
846 std::vector<MicrophoneInfo> aidlInfo;
847 status_t status = statusTFromBinderStatus(mModule->getMicrophones(&aidlInfo));
848 if (status == OK) {
849 mMicrophones.status = Microphones::Status::QUERIED;
850 mMicrophones.info = std::move(aidlInfo);
851 } else if (status == INVALID_OPERATION) {
852 mMicrophones.status = Microphones::Status::NOT_SUPPORTED;
853 } else {
854 ALOGE("%s: Unexpected status from 'IModule.getMicrophones': %d", __func__, status);
855 return {};
856 }
857 }
858 if (mMicrophones.status == Microphones::Status::QUERIED) {
859 return &mMicrophones.info;
860 }
861 return {}; // NOT_SUPPORTED
862}
863
Shunkai Yao51202502022-12-12 06:11:46 +0000864status_t DeviceHalAidl::getMicrophones(
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800865 std::vector<audio_microphone_characteristic_t>* microphones) {
866 if (!microphones) {
867 return BAD_VALUE;
868 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000869 TIME_CHECK();
870 if (!mModule) return NO_INIT;
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800871 auto staticInfo = getMicrophoneInfo();
872 if (!staticInfo) return INVALID_OPERATION;
873 std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
874 emptyDynamicInfo.reserve(staticInfo->size());
875 std::transform(staticInfo->begin(), staticInfo->end(), std::back_inserter(emptyDynamicInfo),
876 [](const auto& info) { return MicrophoneDynamicInfo{ .id = info.id }; });
877 *microphones = VALUE_OR_RETURN_STATUS(
878 ::aidl::android::convertContainers<std::vector<audio_microphone_characteristic_t>>(
879 *staticInfo, emptyDynamicInfo,
880 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t)
881 );
Shunkai Yao51202502022-12-12 06:11:46 +0000882 return OK;
883}
884
Mikhail Naganovd2c7f852023-06-14 18:00:13 -0700885status_t DeviceHalAidl::addDeviceEffect(const struct audio_port_config *device __unused,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000886 sp<EffectHalInterface> effect) {
Shunkai Yao51202502022-12-12 06:11:46 +0000887 if (!effect) {
888 return BAD_VALUE;
889 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000890 TIME_CHECK();
891 if (!mModule) return NO_INIT;
892 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000893 return OK;
894}
Mikhail Naganovd2c7f852023-06-14 18:00:13 -0700895status_t DeviceHalAidl::removeDeviceEffect(const struct audio_port_config *device __unused,
Shunkai Yao51202502022-12-12 06:11:46 +0000896 sp<EffectHalInterface> effect) {
897 if (!effect) {
898 return BAD_VALUE;
899 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000900 TIME_CHECK();
901 if (!mModule) return NO_INIT;
902 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000903 return OK;
904}
905
906status_t DeviceHalAidl::getMmapPolicyInfos(
David Li9cf5e622023-03-21 00:51:10 +0800907 media::audio::common::AudioMMapPolicyType policyType,
908 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000909 TIME_CHECK();
Mikhail Naganov25bc9a22023-04-21 18:48:16 -0700910 AudioMMapPolicyType mmapPolicyType = VALUE_OR_RETURN_STATUS(
911 cpp2ndk_AudioMMapPolicyType(policyType));
David Li9cf5e622023-03-21 00:51:10 +0800912
913 std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
914
915 if (status_t status = statusTFromBinderStatus(
916 mModule->getMmapPolicyInfos(mmapPolicyType, &mmapPolicyInfos)); status != OK) {
917 return status;
918 }
919
920 *policyInfos = VALUE_OR_RETURN_STATUS(
921 convertContainer<std::vector<media::audio::common::AudioMMapPolicyInfo>>(
922 mmapPolicyInfos, ndk2cpp_AudioMMapPolicyInfo));
Shunkai Yao51202502022-12-12 06:11:46 +0000923 return OK;
924}
925
926int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000927 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800928 int32_t mixerBurstCount = 0;
929 if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
930 return mixerBurstCount;
931 }
932 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000933}
934
935int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000936 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800937 int32_t hardwareBurstMinUsec = 0;
938 if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
939 return hardwareBurstMinUsec;
940 }
941 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000942}
943
944error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000945 TIME_CHECK();
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700946 if (!mModule) return NO_INIT;
947 int32_t aidlHwAvSync;
948 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
949 return VALUE_OR_RETURN_STATUS(
950 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +0000951}
952
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000953status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
954 TIME_CHECK();
955 if (!mModule) return NO_INIT;
956 return mModule->dump(fd, Args(args).args(), args.size());
David Li9cf5e622023-03-21 00:51:10 +0800957}
Shunkai Yao51202502022-12-12 06:11:46 +0000958
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700959int32_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000960 TIME_CHECK();
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700961 if (!mModule) return NO_INIT;
962 if (supports == nullptr) {
963 return BAD_VALUE;
964 }
965 return statusTFromBinderStatus(mModule->supportsVariableLatency(supports));
Shunkai Yao51202502022-12-12 06:11:46 +0000966}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000967
jiabin872de702023-04-27 22:04:31 +0000968
969status_t DeviceHalAidl::prepareToDisconnectExternalDevice(const struct audio_port_v7* port) {
970 // There is not AIDL API defined for `prepareToDisconnectExternalDevice`.
971 // Call `setConnectedState` instead.
972 // TODO(b/279824103): call prepareToDisconnectExternalDevice when it is added.
973 const status_t status = setConnectedState(port, false /*connected*/);
974 if (status == NO_ERROR) {
975 mDeviceDisconnectionNotified.insert(port->id);
976 }
977 return status;
978}
979
Mikhail Naganove93a0862023-03-15 17:06:59 -0700980status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
981 TIME_CHECK();
982 if (!mModule) return NO_INIT;
983 if (port == nullptr) {
984 return BAD_VALUE;
985 }
jiabin872de702023-04-27 22:04:31 +0000986 if (!connected && mDeviceDisconnectionNotified.erase(port->id) > 0) {
987 // For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
988 // and then call `setConnectedState`. However, there is no API for
989 // `prepareToDisconnectExternalDevice` yet. In that case, `setConnectedState` will be
990 // called when calling `prepareToDisconnectExternalDevice`. Do not call to the HAL if
991 // previous call is successful. Also remove the cache here to avoid a large cache after
992 // a long run.
993 return NO_ERROR;
994 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700995 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
996 ::aidl::android::AudioPortDirection::INPUT;
997 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
998 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
999 if (aidlPort.ext.getTag() != AudioPortExt::device) {
1000 ALOGE("%s: provided port is not a device port (module %s): %s",
1001 __func__, mInstance.c_str(), aidlPort.toString().c_str());
1002 return BAD_VALUE;
1003 }
1004 if (connected) {
1005 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1006 // Reset the device address to find the "template" port.
1007 matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
1008 auto portsIt = findPort(matchDevice);
1009 if (portsIt == mPorts.end()) {
1010 ALOGW("%s: device port for device %s is not found in the module %s",
1011 __func__, matchDevice.toString().c_str(), mInstance.c_str());
1012 return BAD_VALUE;
1013 }
1014 // Use the ID of the "template" port, use all the information from the provided port.
1015 aidlPort.id = portsIt->first;
1016 AudioPort connectedPort;
1017 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
1018 aidlPort, &connectedPort)));
1019 const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
1020 LOG_ALWAYS_FATAL_IF(!inserted,
1021 "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
1022 __func__, mInstance.c_str(), connectedPort.toString().c_str(),
1023 it->second.toString().c_str());
1024 } else { // !connected
1025 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1026 auto portsIt = findPort(matchDevice);
1027 if (portsIt == mPorts.end()) {
1028 ALOGW("%s: device port for device %s is not found in the module %s",
1029 __func__, matchDevice.toString().c_str(), mInstance.c_str());
1030 return BAD_VALUE;
1031 }
1032 // Any streams opened on the external device must be closed by this time,
1033 // thus we can clean up patches and port configs that were created for them.
1034 resetUnusedPatchesAndPortConfigs();
1035 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
1036 portsIt->second.id)));
1037 mPorts.erase(portsIt);
1038 }
Mikhail Naganov289468a2023-03-29 10:06:15 -07001039 return updateRoutes();
Mikhail Naganove93a0862023-03-15 17:06:59 -07001040}
1041
1042status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
1043 TIME_CHECK();
1044 if (!mModule) return NO_INIT;
1045 ModuleDebug debug{ .simulateDeviceConnections = enabled };
1046 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
1047 // This is important to log as it affects HAL behavior.
1048 if (status == OK) {
1049 ALOGI("%s: set enabled: %d", __func__, enabled);
1050 } else {
1051 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
1052 }
1053 return status;
1054}
1055
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001056bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
1057 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1058 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1059}
1060
1061bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
1062 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1063 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1064 return p.portId == mDefaultInputPortId;
1065 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1066 return p.portId == mDefaultOutputPortId;
1067 }
1068 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1069}
1070
David Lia8675d42023-03-30 21:08:06 +08001071status_t DeviceHalAidl::createOrUpdatePortConfig(
1072 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool* created) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001073 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001074 AudioPortConfig appliedPortConfig;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001075 bool applied = false;
1076 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001077 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001078 if (!applied) {
1079 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001080 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001081 if (!applied) {
1082 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001083 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001084 return NO_INIT;
1085 }
1086 }
David Lia8675d42023-03-30 21:08:06 +08001087
1088 int32_t id = appliedPortConfig.id;
1089 if (requestedPortConfig.id != 0 && requestedPortConfig.id != id) {
1090 LOG_ALWAYS_FATAL("%s: requested port config id %d changed to %d", __func__,
1091 requestedPortConfig.id, id);
1092 }
1093
1094 auto [it, inserted] = mPortConfigs.insert_or_assign(std::move(id),
1095 std::move(appliedPortConfig));
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001096 *result = it;
David Lia8675d42023-03-30 21:08:06 +08001097 *created = inserted;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001098 return OK;
1099}
1100
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001101status_t DeviceHalAidl::filterAndRetrieveBtA2dpParameters(
1102 AudioParameter &keys, AudioParameter *result) {
1103 TIME_CHECK();
1104 if (String8 key = String8(AudioParameter::keyReconfigA2dpSupported); keys.containsKey(key)) {
1105 keys.remove(key);
1106 bool supports;
1107 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1108 mBluetoothA2dp->supportsOffloadReconfiguration(&supports)));
1109 result->addInt(key, supports ? 1 : 0);
1110 }
1111 return OK;
1112}
1113
Mikhail Naganovccc82112023-04-27 18:14:15 -07001114status_t DeviceHalAidl::filterAndUpdateBtA2dpParameters(AudioParameter &parameters) {
1115 TIME_CHECK();
1116 std::optional<bool> a2dpEnabled;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001117 std::optional<std::vector<VendorParameter>> reconfigureOffload;
Mikhail Naganovccc82112023-04-27 18:14:15 -07001118 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1119 parameters, String8(AudioParameter::keyBtA2dpSuspended),
1120 [&a2dpEnabled](const String8& trueOrFalse) {
1121 if (trueOrFalse == AudioParameter::valueTrue) {
1122 a2dpEnabled = false; // 'suspended' == true
1123 return OK;
1124 } else if (trueOrFalse == AudioParameter::valueFalse) {
1125 a2dpEnabled = true; // 'suspended' == false
1126 return OK;
1127 }
1128 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1129 AudioParameter::keyBtA2dpSuspended, trueOrFalse.c_str());
1130 return BAD_VALUE;
1131 }));
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001132 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1133 parameters, String8(AudioParameter::keyReconfigA2dp),
1134 [&](const String8& value) -> status_t {
1135 if (mVendorExt != nullptr) {
1136 std::vector<VendorParameter> result;
1137 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1138 mVendorExt->parseBluetoothA2dpReconfigureOffload(
1139 std::string(value.c_str()), &result)));
1140 reconfigureOffload = std::move(result);
1141 } else {
1142 reconfigureOffload = std::vector<VendorParameter>();
1143 }
1144 return OK;
1145 }));
Mikhail Naganovccc82112023-04-27 18:14:15 -07001146 if (mBluetoothA2dp != nullptr && a2dpEnabled.has_value()) {
1147 return statusTFromBinderStatus(mBluetoothA2dp->setEnabled(a2dpEnabled.value()));
1148 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001149 if (mBluetoothA2dp != nullptr && reconfigureOffload.has_value()) {
1150 return statusTFromBinderStatus(mBluetoothA2dp->reconfigureOffload(
1151 reconfigureOffload.value()));
1152 }
Mikhail Naganovccc82112023-04-27 18:14:15 -07001153 return OK;
1154}
1155
1156status_t DeviceHalAidl::filterAndUpdateBtHfpParameters(AudioParameter &parameters) {
1157 TIME_CHECK();
1158 IBluetooth::HfpConfig hfpConfig;
1159 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1160 parameters, String8(AudioParameter::keyBtHfpEnable),
1161 [&hfpConfig](const String8& trueOrFalse) {
1162 if (trueOrFalse == AudioParameter::valueTrue) {
1163 hfpConfig.isEnabled = Boolean{ .value = true };
1164 return OK;
1165 } else if (trueOrFalse == AudioParameter::valueFalse) {
1166 hfpConfig.isEnabled = Boolean{ .value = false };
1167 return OK;
1168 }
1169 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1170 AudioParameter::keyBtHfpEnable, trueOrFalse.c_str());
1171 return BAD_VALUE;
1172 }));
1173 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1174 parameters, String8(AudioParameter::keyBtHfpSamplingRate),
1175 [&hfpConfig](int sampleRate) {
1176 return sampleRate > 0 ?
1177 hfpConfig.sampleRate = Int{ .value = sampleRate }, OK : BAD_VALUE;
1178 }));
1179 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1180 parameters, String8(AudioParameter::keyBtHfpVolume),
1181 [&hfpConfig](int volume0to15) {
1182 if (volume0to15 >= 0 && volume0to15 <= 15) {
1183 hfpConfig.volume = Float{ .value = volume0to15 / 15.0f };
1184 return OK;
1185 }
1186 return BAD_VALUE;
1187 }));
1188 if (mBluetooth != nullptr && hfpConfig != IBluetooth::HfpConfig{}) {
1189 IBluetooth::HfpConfig newHfpConfig;
1190 return statusTFromBinderStatus(mBluetooth->setHfpConfig(hfpConfig, &newHfpConfig));
1191 }
1192 return OK;
1193}
1194
1195status_t DeviceHalAidl::filterAndUpdateBtLeParameters(AudioParameter &parameters) {
1196 TIME_CHECK();
1197 std::optional<bool> leEnabled;
1198 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1199 parameters, String8(AudioParameter::keyBtLeSuspended),
1200 [&leEnabled](const String8& trueOrFalse) {
1201 if (trueOrFalse == AudioParameter::valueTrue) {
1202 leEnabled = false; // 'suspended' == true
1203 return OK;
1204 } else if (trueOrFalse == AudioParameter::valueFalse) {
1205 leEnabled = true; // 'suspended' == false
1206 return OK;
1207 }
1208 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1209 AudioParameter::keyBtLeSuspended, trueOrFalse.c_str());
1210 return BAD_VALUE;
1211 }));
1212 if (mBluetoothLe != nullptr && leEnabled.has_value()) {
1213 return statusTFromBinderStatus(mBluetoothLe->setEnabled(leEnabled.value()));
1214 }
1215 return OK;
1216}
1217
1218status_t DeviceHalAidl::filterAndUpdateBtScoParameters(AudioParameter &parameters) {
1219 TIME_CHECK();
1220 IBluetooth::ScoConfig scoConfig;
1221 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1222 parameters, String8(AudioParameter::keyBtSco),
1223 [&scoConfig](const String8& onOrOff) {
1224 if (onOrOff == AudioParameter::valueOn) {
1225 scoConfig.isEnabled = Boolean{ .value = true };
1226 return OK;
1227 } else if (onOrOff == AudioParameter::valueOff) {
1228 scoConfig.isEnabled = Boolean{ .value = false };
1229 return OK;
1230 }
1231 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1232 AudioParameter::keyBtSco, onOrOff.c_str());
1233 return BAD_VALUE;
1234 }));
1235 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1236 parameters, String8(AudioParameter::keyBtScoHeadsetName),
1237 [&scoConfig](const String8& name) {
1238 scoConfig.debugName = name;
1239 return OK;
1240 }));
1241 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1242 parameters, String8(AudioParameter::keyBtNrec),
1243 [&scoConfig](const String8& onOrOff) {
1244 if (onOrOff == AudioParameter::valueOn) {
1245 scoConfig.isNrecEnabled = Boolean{ .value = true };
1246 return OK;
1247 } else if (onOrOff == AudioParameter::valueOff) {
1248 scoConfig.isNrecEnabled = Boolean{ .value = false };
1249 return OK;
1250 }
1251 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1252 AudioParameter::keyBtNrec, onOrOff.c_str());
1253 return BAD_VALUE;
1254 }));
1255 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1256 parameters, String8(AudioParameter::keyBtScoWb),
1257 [&scoConfig](const String8& onOrOff) {
1258 if (onOrOff == AudioParameter::valueOn) {
1259 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO_WB;
1260 return OK;
1261 } else if (onOrOff == AudioParameter::valueOff) {
1262 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO;
1263 return OK;
1264 }
1265 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1266 AudioParameter::keyBtScoWb, onOrOff.c_str());
1267 return BAD_VALUE;
1268 }));
1269 if (mBluetooth != nullptr && scoConfig != IBluetooth::ScoConfig{}) {
1270 IBluetooth::ScoConfig newScoConfig;
1271 return statusTFromBinderStatus(mBluetooth->setScoConfig(scoConfig, &newScoConfig));
1272 }
1273 return OK;
1274}
1275
Mikhail Naganove92c34b2023-05-31 14:24:48 -07001276status_t DeviceHalAidl::filterAndUpdateScreenParameters(AudioParameter &parameters) {
1277 TIME_CHECK();
1278 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1279 parameters, String8(AudioParameter::keyScreenState),
1280 [&](const String8& onOrOff) -> status_t {
1281 std::optional<bool> isTurnedOn;
1282 if (onOrOff == AudioParameter::valueOn) {
1283 isTurnedOn = true;
1284 } else if (onOrOff == AudioParameter::valueOff) {
1285 isTurnedOn = false;
1286 }
1287 if (!isTurnedOn.has_value()) {
1288 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1289 AudioParameter::keyScreenState, onOrOff.c_str());
1290 return BAD_VALUE;
1291 }
1292 return statusTFromBinderStatus(
1293 mModule->updateScreenState(isTurnedOn.value()));
1294 }));
1295 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1296 parameters, String8(AudioParameter::keyScreenRotation),
1297 [&](int rotationDegrees) -> status_t {
1298 IModule::ScreenRotation rotation;
1299 switch (rotationDegrees) {
1300 case 0: rotation = IModule::ScreenRotation::DEG_0; break;
1301 case 90: rotation = IModule::ScreenRotation::DEG_90; break;
1302 case 180: rotation = IModule::ScreenRotation::DEG_180; break;
1303 case 270: rotation = IModule::ScreenRotation::DEG_270; break;
1304 default:
1305 ALOGE("setParameters: parameter key \"%s\" has invalid value %d",
1306 AudioParameter::keyScreenRotation, rotationDegrees);
1307 return BAD_VALUE;
1308 }
1309 return statusTFromBinderStatus(mModule->updateScreenRotation(rotation));
1310 }));
1311 return OK;
1312}
1313
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001314status_t DeviceHalAidl::findOrCreatePatch(
1315 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
1316 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
1317 requestedPatch.sourcePortConfigIds.end());
1318 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
1319 requestedPatch.sinkPortConfigIds.end());
1320 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
1321}
1322
1323status_t DeviceHalAidl::findOrCreatePatch(
1324 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
1325 AudioPatch* patch, bool* created) {
1326 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
1327 if (patchIt == mPatches.end()) {
1328 TIME_CHECK();
1329 AudioPatch requestedPatch, appliedPatch;
1330 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
1331 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
1332 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
1333 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
1334 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
1335 requestedPatch, &appliedPatch)));
1336 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
1337 *created = true;
1338 } else {
1339 *created = false;
1340 }
1341 *patch = patchIt->second;
1342 return OK;
1343}
1344
jiabin9c07faf2023-04-26 22:00:44 +00001345status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device, const AudioConfig* config,
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001346 AudioPortConfig* portConfig, bool* created) {
1347 auto portConfigIt = findPortConfig(device);
1348 if (portConfigIt == mPortConfigs.end()) {
1349 auto portsIt = findPort(device);
1350 if (portsIt == mPorts.end()) {
1351 ALOGE("%s: device port for device %s is not found in the module %s",
1352 __func__, device.toString().c_str(), mInstance.c_str());
1353 return BAD_VALUE;
1354 }
1355 AudioPortConfig requestedPortConfig;
1356 requestedPortConfig.portId = portsIt->first;
jiabin9c07faf2023-04-26 22:00:44 +00001357 if (config != nullptr) {
1358 setPortConfigFromConfig(&requestedPortConfig, *config);
1359 }
David Lia8675d42023-03-30 21:08:06 +08001360 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1361 created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001362 } else {
1363 *created = false;
1364 }
1365 *portConfig = portConfigIt->second;
1366 return OK;
1367}
1368
1369status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001370 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001371 AudioSource source, const std::set<int32_t>& destinationPortIds,
1372 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001373 // These flags get removed one by one in this order when retrying port finding.
1374 static const std::vector<AudioInputFlags> kOptionalInputFlags{
1375 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001376 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001377 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001378 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
1379 AudioIoFlags matchFlags = flags.value();
Mikhail Naganov289468a2023-03-29 10:06:15 -07001380 auto portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001381 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
1382 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
1383 if (!isBitPositionFlagSet(
1384 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
1385 ++optionalInputFlagsIt;
1386 continue;
1387 }
1388 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
1389 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
Mikhail Naganov289468a2023-03-29 10:06:15 -07001390 portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001391 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
1392 "retried with flags %s", __func__, config.toString().c_str(),
1393 flags.value().toString().c_str(), mInstance.c_str(),
1394 matchFlags.toString().c_str());
1395 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001396 if (portsIt == mPorts.end()) {
1397 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001398 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001399 mInstance.c_str());
1400 return BAD_VALUE;
1401 }
1402 AudioPortConfig requestedPortConfig;
1403 requestedPortConfig.portId = portsIt->first;
1404 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001405 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001406 if (matchFlags.getTag() == AudioIoFlags::Tag::input
1407 && source != AudioSource::SYS_RESERVED_INVALID) {
1408 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
1409 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
1410 }
David Lia8675d42023-03-30 21:08:06 +08001411 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1412 created));
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001413 } else if (!flags.has_value()) {
1414 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
1415 "and was not created as flags are not specified",
1416 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
1417 return BAD_VALUE;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001418 } else {
David Lia8675d42023-03-30 21:08:06 +08001419 AudioPortConfig requestedPortConfig = portConfigIt->second;
1420 if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
1421 AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
1422 if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
1423 source != AudioSource::SYS_RESERVED_INVALID) {
1424 mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
1425 }
1426 }
1427
1428 if (requestedPortConfig != portConfigIt->second) {
1429 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1430 created));
1431 } else {
1432 *created = false;
1433 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001434 }
1435 *portConfig = portConfigIt->second;
1436 return OK;
1437}
1438
1439status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001440 const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
1441 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001442 using Tag = AudioPortExt::Tag;
1443 if (requestedPortConfig.ext.getTag() == Tag::mix) {
1444 if (const auto& p = requestedPortConfig;
1445 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001446 !p.format.has_value()) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001447 ALOGW("%s: provided mix port config is not fully specified: %s",
1448 __func__, p.toString().c_str());
1449 return BAD_VALUE;
1450 }
1451 AudioConfig config;
1452 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001453 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
1454 AudioPortMixExtUseCase::Tag::source ?
1455 requestedPortConfig.ext.get<Tag::mix>().usecase.
1456 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001457 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001458 requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
1459 portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001460 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
1461 return findOrCreatePortConfig(
jiabin9c07faf2023-04-26 22:00:44 +00001462 requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
1463 portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001464 }
1465 ALOGW("%s: unsupported audio port config: %s",
1466 __func__, requestedPortConfig.toString().c_str());
1467 return BAD_VALUE;
1468}
1469
1470DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
1471 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
1472 return std::find_if(mPatches.begin(), mPatches.end(),
1473 [&](const auto& pair) {
1474 const auto& p = pair.second;
1475 std::set<int32_t> patchSrcs(
1476 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
1477 std::set<int32_t> patchSinks(
1478 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
1479 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
1480}
1481
1482DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001483 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1484 return mPorts.find(mDefaultInputPortId);
1485 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1486 return mPorts.find(mDefaultOutputPortId);
1487 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001488 return std::find_if(mPorts.begin(), mPorts.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001489 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001490}
1491
1492DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001493 const AudioConfig& config, const AudioIoFlags& flags,
1494 const std::set<int32_t>& destinationPortIds) {
Mikhail Naganove93a0862023-03-15 17:06:59 -07001495 auto belongsToProfile = [&config](const AudioProfile& prof) {
1496 return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
1497 (config.base.channelMask.getTag() == AudioChannelLayout::none ||
1498 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
1499 config.base.channelMask) != prof.channelMasks.end()) &&
1500 (config.base.sampleRate == 0 ||
1501 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
1502 config.base.sampleRate) != prof.sampleRates.end());
1503 };
jiabin9c07faf2023-04-26 22:00:44 +00001504 static const std::vector<AudioOutputFlags> kOptionalOutputFlags{AudioOutputFlags::BIT_PERFECT};
1505 int optionalFlags = 0;
1506 auto flagMatches = [&flags, &optionalFlags](const AudioIoFlags& portFlags) {
1507 // Ports should be able to match if the optional flags are not requested.
1508 return portFlags == flags ||
1509 (portFlags.getTag() == AudioIoFlags::Tag::output &&
1510 AudioIoFlags::make<AudioIoFlags::Tag::output>(
1511 portFlags.get<AudioIoFlags::Tag::output>() &
1512 ~optionalFlags) == flags);
1513 };
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001514 auto matcher = [&](const auto& pair) {
1515 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001516 return p.ext.getTag() == AudioPortExt::Tag::mix &&
jiabin9c07faf2023-04-26 22:00:44 +00001517 flagMatches(p.flags) &&
Mikhail Naganov289468a2023-03-29 10:06:15 -07001518 (destinationPortIds.empty() ||
1519 std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
1520 [&](const int32_t destId) { return mRoutingMatrix.count(
1521 std::make_pair(p.id, destId)) != 0; })) &&
Mikhail Naganove93a0862023-03-15 17:06:59 -07001522 (p.profiles.empty() ||
1523 std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
1524 p.profiles.end()); };
jiabin9c07faf2023-04-26 22:00:44 +00001525 auto result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1526 if (result == mPorts.end() && flags.getTag() == AudioIoFlags::Tag::output) {
1527 auto optionalOutputFlagsIt = kOptionalOutputFlags.begin();
1528 while (result == mPorts.end() && optionalOutputFlagsIt != kOptionalOutputFlags.end()) {
1529 if (isBitPositionFlagSet(
1530 flags.get<AudioIoFlags::Tag::output>(), *optionalOutputFlagsIt)) {
1531 // If the flag is set by the request, it must be matched.
1532 ++optionalOutputFlagsIt;
1533 continue;
1534 }
1535 optionalFlags |= makeBitPositionFlagMask(*optionalOutputFlagsIt++);
1536 result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1537 ALOGI("%s: port for config %s, flags %s was not found in the module %s, "
1538 "retried with excluding optional flags %#x", __func__, config.toString().c_str(),
1539 flags.toString().c_str(), mInstance.c_str(), optionalFlags);
1540 }
1541 }
1542 return result;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001543}
1544
1545DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001546 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001547 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001548}
1549
1550DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001551 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001552 using Tag = AudioPortExt::Tag;
1553 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
1554 [&](const auto& pair) {
1555 const auto& p = pair.second;
1556 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
1557 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
1558 !p.format.has_value() || !p.flags.has_value(),
1559 "%s: stored mix port config is not fully specified: %s",
1560 __func__, p.toString().c_str());
1561 return p.ext.getTag() == Tag::mix &&
1562 isConfigEqualToPortConfig(config, p) &&
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001563 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001564 p.ext.template get<Tag::mix>().handle == ioHandle; });
1565}
Mikhail Naganove93a0862023-03-15 17:06:59 -07001566
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001567void DeviceHalAidl::resetPatch(int32_t patchId) {
1568 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1569 mPatches.erase(it);
1570 TIME_CHECK();
1571 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1572 ALOGE("%s: error while resetting patch %d: %s",
1573 __func__, patchId, status.getDescription().c_str());
1574 }
1575 return;
1576 }
1577 ALOGE("%s: patch id %d not found", __func__, patchId);
1578}
1579
1580void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1581 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1582 mPortConfigs.erase(it);
1583 TIME_CHECK();
1584 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1585 !status.isOk()) {
1586 ALOGE("%s: error while resetting port config %d: %s",
1587 __func__, portConfigId, status.getDescription().c_str());
1588 }
1589 return;
1590 }
1591 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1592}
1593
Mikhail Naganove93a0862023-03-15 17:06:59 -07001594void DeviceHalAidl::resetUnusedPatches() {
1595 // Since patches can be created independently of streams via 'createAudioPatch',
1596 // here we only clean up patches for released streams.
1597 for (auto it = mStreams.begin(); it != mStreams.end(); ) {
1598 if (auto streamSp = it->first.promote(); streamSp) {
1599 ++it;
1600 } else {
1601 resetPatch(it->second);
1602 it = mStreams.erase(it);
1603 }
1604 }
1605}
1606
1607void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
1608 resetUnusedPatches();
1609 resetUnusedPortConfigs();
1610}
1611
1612void DeviceHalAidl::resetUnusedPortConfigs() {
1613 // The assumption is that port configs are used to create patches
1614 // (or to open streams, but that involves creation of patches, too). Thus,
1615 // orphaned port configs can and should be reset.
1616 std::set<int32_t> portConfigIds;
1617 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
1618 std::inserter(portConfigIds, portConfigIds.end()),
1619 [](const auto& pcPair) { return pcPair.first; });
1620 for (const auto& p : mPatches) {
1621 for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
1622 for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
1623 }
jiabin9c07faf2023-04-26 22:00:44 +00001624 for (int32_t id : mInitialPortConfigIds) {
1625 portConfigIds.erase(id);
1626 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001627 for (int32_t id : portConfigIds) resetPortConfig(id);
1628}
1629
Mikhail Naganov289468a2023-03-29 10:06:15 -07001630status_t DeviceHalAidl::updateRoutes() {
1631 TIME_CHECK();
Mikhail Naganov289468a2023-03-29 10:06:15 -07001632 RETURN_STATUS_IF_ERROR(
Mikhail Naganovf83b9742023-04-24 13:06:04 -07001633 statusTFromBinderStatus(mModule->getAudioRoutes(&mRoutes)));
1634 ALOGW_IF(mRoutes.empty(), "%s: module %s returned an empty list of audio routes",
Mikhail Naganov289468a2023-03-29 10:06:15 -07001635 __func__, mInstance.c_str());
1636 mRoutingMatrix.clear();
Mikhail Naganovf83b9742023-04-24 13:06:04 -07001637 for (const auto& r : mRoutes) {
Mikhail Naganov289468a2023-03-29 10:06:15 -07001638 for (auto portId : r.sourcePortIds) {
1639 mRoutingMatrix.emplace(r.sinkPortId, portId);
1640 mRoutingMatrix.emplace(portId, r.sinkPortId);
1641 }
1642 }
1643 return OK;
1644}
1645
Mikhail Naganovdfd594e2023-02-08 16:59:41 -08001646void DeviceHalAidl::clearCallbacks(void* cookie) {
1647 std::lock_guard l(mLock);
1648 mCallbacks.erase(cookie);
1649}
1650
1651sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1652 return getCallbackImpl(cookie, &Callbacks::out);
1653}
1654
1655void DeviceHalAidl::setStreamOutCallback(
1656 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1657 setCallbackImpl(cookie, &Callbacks::out, cb);
1658}
1659
1660sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1661 void* cookie) {
1662 return getCallbackImpl(cookie, &Callbacks::event);
1663}
1664
1665void DeviceHalAidl::setStreamOutEventCallback(
1666 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1667 setCallbackImpl(cookie, &Callbacks::event, cb);
1668}
1669
1670sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1671 void* cookie) {
1672 return getCallbackImpl(cookie, &Callbacks::latency);
1673}
1674
1675void DeviceHalAidl::setStreamOutLatencyModeCallback(
1676 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1677 setCallbackImpl(cookie, &Callbacks::latency, cb);
1678}
1679
1680template<class C>
1681sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1682 std::lock_guard l(mLock);
1683 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1684 return ((it->second).*field).promote();
1685 }
1686 return nullptr;
1687}
1688template<class C>
1689void DeviceHalAidl::setCallbackImpl(
1690 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1691 std::lock_guard l(mLock);
1692 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1693 (it->second).*field = cb;
1694 }
1695}
1696
Mikhail Naganov31d46652023-01-10 18:29:25 +00001697} // namespace android