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