blob: 922604f4a9711272bee27254500753a2af7ee837 [file] [log] [blame]
Shunkai Yao51202502022-12-12 06:11:46 +00001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "DeviceHalAidl"
Mikhail Naganov89a9f742023-01-30 12:33:18 -080018// #define LOG_NDEBUG 0
Shunkai Yao51202502022-12-12 06:11:46 +000019
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080020#include <algorithm>
21#include <forward_list>
22
Mikhail Naganovdfd594e2023-02-08 16:59:41 -080023#include <aidl/android/hardware/audio/core/BnStreamCallback.h>
24#include <aidl/android/hardware/audio/core/BnStreamOutEventCallback.h>
Mikhail Naganovfab697c2023-01-11 19:33:13 +000025#include <aidl/android/hardware/audio/core/StreamDescriptor.h>
26#include <error/expected_utils.h>
27#include <media/AidlConversionCppNdk.h>
Mikhail Naganov25bc9a22023-04-21 18:48:16 -070028#include <media/AidlConversionNdkCpp.h>
Mikhail Naganovfab697c2023-01-11 19:33:13 +000029#include <media/AidlConversionUtil.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000030#include <mediautils/TimeCheck.h>
Mikhail Naganov89a9f742023-01-30 12:33:18 -080031#include <Utils.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000032#include <utils/Log.h>
Shunkai Yao51202502022-12-12 06:11:46 +000033
Mikhail Naganov31d46652023-01-10 18:29:25 +000034#include "DeviceHalAidl.h"
35#include "StreamHalAidl.h"
36
Mikhail Naganovfab697c2023-01-11 19:33:13 +000037using aidl::android::aidl_utils::statusTFromBinderStatus;
Mikhail Naganovccc82112023-04-27 18:14:15 -070038using aidl::android::media::audio::common::Boolean;
Mikhail Naganove93a0862023-03-15 17:06:59 -070039using aidl::android::media::audio::common::AudioChannelLayout;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080040using aidl::android::media::audio::common::AudioConfig;
41using aidl::android::media::audio::common::AudioDevice;
David Li9cf5e622023-03-21 00:51:10 +080042using aidl::android::media::audio::common::AudioDeviceAddress;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080043using aidl::android::media::audio::common::AudioDeviceType;
Mikhail Naganove93a0862023-03-15 17:06:59 -070044using aidl::android::media::audio::common::AudioFormatType;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080045using aidl::android::media::audio::common::AudioInputFlags;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080046using aidl::android::media::audio::common::AudioIoFlags;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -080047using aidl::android::media::audio::common::AudioLatencyMode;
David Li9cf5e622023-03-21 00:51:10 +080048using aidl::android::media::audio::common::AudioMMapPolicy;
49using aidl::android::media::audio::common::AudioMMapPolicyInfo;
50using aidl::android::media::audio::common::AudioMMapPolicyType;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000051using aidl::android::media::audio::common::AudioMode;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080052using aidl::android::media::audio::common::AudioOutputFlags;
53using aidl::android::media::audio::common::AudioPort;
54using aidl::android::media::audio::common::AudioPortConfig;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080055using aidl::android::media::audio::common::AudioPortDeviceExt;
David Li9cf5e622023-03-21 00:51:10 +080056using aidl::android::media::audio::common::AudioPortExt;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -080057using aidl::android::media::audio::common::AudioPortMixExt;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -080058using aidl::android::media::audio::common::AudioPortMixExtUseCase;
Mikhail Naganove93a0862023-03-15 17:06:59 -070059using aidl::android::media::audio::common::AudioProfile;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080060using aidl::android::media::audio::common::AudioSource;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000061using aidl::android::media::audio::common::Float;
David Li9cf5e622023-03-21 00:51:10 +080062using aidl::android::media::audio::common::Int;
63using aidl::android::media::audio::common::MicrophoneDynamicInfo;
64using aidl::android::media::audio::common::MicrophoneInfo;
Mikhail Naganov6352e822023-03-09 18:22:36 -080065using aidl::android::hardware::audio::common::getFrameSizeInBytes;
66using aidl::android::hardware::audio::common::isBitPositionFlagSet;
Mikhail Naganove93a0862023-03-15 17:06:59 -070067using aidl::android::hardware::audio::common::isDefaultAudioFormat;
Mikhail Naganov6352e822023-03-09 18:22:36 -080068using aidl::android::hardware::audio::common::makeBitPositionFlagMask;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080069using aidl::android::hardware::audio::common::RecordTrackMetadata;
70using aidl::android::hardware::audio::core::AudioPatch;
Mikhail Naganov289468a2023-03-29 10:06:15 -070071using aidl::android::hardware::audio::core::AudioRoute;
Mikhail Naganovccc82112023-04-27 18:14:15 -070072using aidl::android::hardware::audio::core::IBluetooth;
73using aidl::android::hardware::audio::core::IBluetoothA2dp;
74using aidl::android::hardware::audio::core::IBluetoothLe;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000075using aidl::android::hardware::audio::core::IModule;
76using aidl::android::hardware::audio::core::ITelephony;
Mikhail Naganove93a0862023-03-15 17:06:59 -070077using aidl::android::hardware::audio::core::ModuleDebug;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000078using aidl::android::hardware::audio::core::StreamDescriptor;
Mikhail Naganov31d46652023-01-10 18:29:25 +000079
80namespace android {
81
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080082namespace {
83
84bool isConfigEqualToPortConfig(const AudioConfig& config, const AudioPortConfig& portConfig) {
85 return portConfig.sampleRate.value().value == config.base.sampleRate &&
86 portConfig.channelMask.value() == config.base.channelMask &&
87 portConfig.format.value() == config.base.format;
88}
89
90void setConfigFromPortConfig(AudioConfig* config, const AudioPortConfig& portConfig) {
91 config->base.sampleRate = portConfig.sampleRate.value().value;
92 config->base.channelMask = portConfig.channelMask.value();
93 config->base.format = portConfig.format.value();
94}
95
96void setPortConfigFromConfig(AudioPortConfig* portConfig, const AudioConfig& config) {
97 portConfig->sampleRate = Int{ .value = config.base.sampleRate };
98 portConfig->channelMask = config.base.channelMask;
99 portConfig->format = config.base.format;
100}
101
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700102// Note: these converters are for types defined in different AIDL files. Although these
103// AIDL files are copies of each other, however formally these are different types
104// thus we don't use a conversion via a parcelable.
105ConversionResult<media::AudioRoute> ndk2cpp_AudioRoute(const AudioRoute& ndk) {
106 media::AudioRoute cpp;
107 cpp.sourcePortIds.insert(
108 cpp.sourcePortIds.end(), ndk.sourcePortIds.begin(), ndk.sourcePortIds.end());
109 cpp.sinkPortId = ndk.sinkPortId;
110 cpp.isExclusive = ndk.isExclusive;
David Li9cf5e622023-03-21 00:51:10 +0800111 return cpp;
112}
113
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700114template<typename T>
115std::shared_ptr<T> retrieveSubInterface(const std::shared_ptr<IModule>& module,
116 ::ndk::ScopedAStatus (IModule::*getT)(std::shared_ptr<T>*)) {
117 if (module != nullptr) {
118 std::shared_ptr<T> instance;
119 if (auto status = (module.get()->*getT)(&instance); status.isOk()) {
120 return instance;
121 }
122 }
123 return nullptr;
124}
125
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800126} // namespace
127
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700128DeviceHalAidl::DeviceHalAidl(const std::string& instance, const std::shared_ptr<IModule>& module)
129 : ConversionHelperAidl("DeviceHalAidl"),
130 mInstance(instance), mModule(module),
Mikhail Naganovccc82112023-04-27 18:14:15 -0700131 mTelephony(retrieveSubInterface<ITelephony>(module, &IModule::getTelephony)),
132 mBluetooth(retrieveSubInterface<IBluetooth>(module, &IModule::getBluetooth)),
133 mBluetoothA2dp(retrieveSubInterface<IBluetoothA2dp>(module, &IModule::getBluetoothA2dp)),
134 mBluetoothLe(retrieveSubInterface<IBluetoothLe>(module, &IModule::getBluetoothLe)) {
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700135}
136
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700137status_t DeviceHalAidl::getAudioPorts(std::vector<media::audio::common::AudioPort> *ports) {
Mikhail Naganov9e459d72023-05-05 17:36:39 -0700138 return ::aidl::android::convertContainer(mPorts, ports,
139 [](const Ports::value_type& pair) { return ndk2cpp_AudioPort(pair.second); });
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700140}
141
142status_t DeviceHalAidl::getAudioRoutes(std::vector<media::AudioRoute> *routes) {
143 *routes = VALUE_OR_RETURN_STATUS(
144 ::aidl::android::convertContainer<std::vector<media::AudioRoute>>(
145 mRoutes, ndk2cpp_AudioRoute));
146 return OK;
147}
148
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700149status_t DeviceHalAidl::getSupportedModes(std::vector<media::audio::common::AudioMode> *modes) {
150 TIME_CHECK();
151 if (modes == nullptr) {
152 return BAD_VALUE;
153 }
154 if (mModule == nullptr) return NO_INIT;
155 if (mTelephony == nullptr) return INVALID_OPERATION;
156 std::vector<AudioMode> aidlModes;
157 RETURN_STATUS_IF_ERROR(
158 statusTFromBinderStatus(mTelephony->getSupportedAudioModes(&aidlModes)));
159 *modes = VALUE_OR_RETURN_STATUS(
160 ::aidl::android::convertContainer<std::vector<media::audio::common::AudioMode>>(
161 aidlModes, ndk2cpp_AudioMode));
162 return OK;
163}
164
Mikhail Naganov31d46652023-01-10 18:29:25 +0000165status_t DeviceHalAidl::getSupportedDevices(uint32_t*) {
166 // Obsolete.
167 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +0000168}
169
170status_t DeviceHalAidl::initCheck() {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800171 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000172 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800173 std::vector<AudioPort> ports;
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700174 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800175 ALOGW_IF(ports.empty(), "%s: module %s returned an empty list of audio ports",
176 __func__, mInstance.c_str());
177 std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()),
178 [](const auto& p) { return std::make_pair(p.id, p); });
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800179 mDefaultInputPortId = mDefaultOutputPortId = -1;
180 const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
181 for (const auto& pair : mPorts) {
182 const auto& p = pair.second;
183 if (p.ext.getTag() == AudioPortExt::Tag::device &&
184 (p.ext.get<AudioPortExt::Tag::device>().flags & defaultDeviceFlag) != 0) {
185 if (p.flags.getTag() == AudioIoFlags::Tag::input) {
186 mDefaultInputPortId = p.id;
187 } else if (p.flags.getTag() == AudioIoFlags::Tag::output) {
188 mDefaultOutputPortId = p.id;
189 }
190 }
191 }
192 ALOGI("%s: module %s default port ids: input %d, output %d",
193 __func__, mInstance.c_str(), mDefaultInputPortId, mDefaultOutputPortId);
Mikhail Naganov289468a2023-03-29 10:06:15 -0700194 RETURN_STATUS_IF_ERROR(updateRoutes());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800195 std::vector<AudioPortConfig> portConfigs;
196 RETURN_STATUS_IF_ERROR(
197 statusTFromBinderStatus(mModule->getAudioPortConfigs(&portConfigs))); // OK if empty
198 std::transform(portConfigs.begin(), portConfigs.end(),
199 std::inserter(mPortConfigs, mPortConfigs.end()),
200 [](const auto& p) { return std::make_pair(p.id, p); });
jiabin9c07faf2023-04-26 22:00:44 +0000201 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
202 std::inserter(mInitialPortConfigIds, mInitialPortConfigIds.end()),
203 [](const auto& pcPair) { return pcPair.first; });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800204 std::vector<AudioPatch> patches;
205 RETURN_STATUS_IF_ERROR(
206 statusTFromBinderStatus(mModule->getAudioPatches(&patches))); // OK if empty
207 std::transform(patches.begin(), patches.end(),
208 std::inserter(mPatches, mPatches.end()),
209 [](const auto& p) { return std::make_pair(p.id, p); });
Shunkai Yao51202502022-12-12 06:11:46 +0000210 return OK;
211}
212
213status_t DeviceHalAidl::setVoiceVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000214 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000215 if (!mModule) return NO_INIT;
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700216 if (mTelephony == nullptr) return INVALID_OPERATION;
217 ITelephony::TelecomConfig inConfig{ .voiceVolume = Float{volume} }, outConfig;
218 RETURN_STATUS_IF_ERROR(
219 statusTFromBinderStatus(mTelephony->setTelecomConfig(inConfig, &outConfig)));
220 ALOGW_IF(outConfig.voiceVolume.has_value() && volume != outConfig.voiceVolume.value().value,
221 "%s: the resulting voice volume %f is not the same as requested %f",
222 __func__, outConfig.voiceVolume.value().value, volume);
223 return OK;
Shunkai Yao51202502022-12-12 06:11:46 +0000224}
225
226status_t DeviceHalAidl::setMasterVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000227 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000228 if (!mModule) return NO_INIT;
229 return statusTFromBinderStatus(mModule->setMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000230}
231
232status_t DeviceHalAidl::getMasterVolume(float *volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000233 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000234 if (!mModule) return NO_INIT;
235 return statusTFromBinderStatus(mModule->getMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000236}
237
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000238status_t DeviceHalAidl::setMode(audio_mode_t mode) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000239 TIME_CHECK();
240 if (!mModule) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000241 AudioMode audioMode = VALUE_OR_FATAL(::aidl::android::legacy2aidl_audio_mode_t_AudioMode(mode));
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700242 if (mTelephony != nullptr) {
243 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mTelephony->switchAudioMode(audioMode)));
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000244 }
245 return statusTFromBinderStatus(mModule->updateAudioMode(audioMode));
Shunkai Yao51202502022-12-12 06:11:46 +0000246}
247
248status_t DeviceHalAidl::setMicMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000249 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000250 if (!mModule) return NO_INIT;
251 return statusTFromBinderStatus(mModule->setMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000252}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000253
Shunkai Yao51202502022-12-12 06:11:46 +0000254status_t DeviceHalAidl::getMicMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000255 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000256 if (!mModule) return NO_INIT;
257 return statusTFromBinderStatus(mModule->getMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000258}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000259
Shunkai Yao51202502022-12-12 06:11:46 +0000260status_t DeviceHalAidl::setMasterMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000261 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000262 if (!mModule) return NO_INIT;
263 return statusTFromBinderStatus(mModule->setMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000264}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000265
Shunkai Yao51202502022-12-12 06:11:46 +0000266status_t DeviceHalAidl::getMasterMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000267 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000268 if (!mModule) return NO_INIT;
269 return statusTFromBinderStatus(mModule->getMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000270}
271
Mikhail Naganovccc82112023-04-27 18:14:15 -0700272status_t DeviceHalAidl::setParameters(const String8& kvPairs) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000273 if (!mModule) return NO_INIT;
Mikhail Naganovccc82112023-04-27 18:14:15 -0700274 AudioParameter parameters(kvPairs);
275 ALOGD("%s: parameters: \"%s\"", __func__, parameters.toString().c_str());
276
277 if (status_t status = filterAndUpdateBtA2dpParameters(parameters); status != OK) {
278 ALOGW("%s: filtering or updating BT A2DP parameters failed: %d", __func__, status);
279 }
280 if (status_t status = filterAndUpdateBtHfpParameters(parameters); status != OK) {
281 ALOGW("%s: filtering or updating BT HFP parameters failed: %d", __func__, status);
282 }
283 if (status_t status = filterAndUpdateBtLeParameters(parameters); status != OK) {
284 ALOGW("%s: filtering or updating BT LE parameters failed: %d", __func__, status);
285 }
286 if (status_t status = filterAndUpdateBtScoParameters(parameters); status != OK) {
287 ALOGW("%s: filtering or updating BT SCO parameters failed: %d", __func__, status);
288 }
289
290 ALOGW_IF(parameters.size() != 0, "%s: unknown parameters, ignored: \"%s\"",
291 __func__, parameters.toString().c_str());
Shunkai Yao51202502022-12-12 06:11:46 +0000292 return OK;
293}
294
Mikhail Naganov31d46652023-01-10 18:29:25 +0000295status_t DeviceHalAidl::getParameters(const String8& keys __unused, String8 *values) {
296 TIME_CHECK();
Mikhail Naganovccc82112023-04-27 18:14:15 -0700297 // FIXME(b/278976019): Support keyReconfigA2dpSupported via vendor plugin
Mikhail Naganov31d46652023-01-10 18:29:25 +0000298 values->clear();
299 if (!mModule) return NO_INIT;
300 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000301 return OK;
302}
303
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800304namespace {
305
306class Cleanup {
307 public:
308 typedef void (DeviceHalAidl::*Cleaner)(int32_t);
309
310 Cleanup(DeviceHalAidl* device, Cleaner cleaner, int32_t id) :
311 mDevice(device), mCleaner(cleaner), mId(id) {}
312 ~Cleanup() { clean(); }
313 void clean() {
314 if (mDevice != nullptr) (mDevice->*mCleaner)(mId);
315 disarm();
316 }
317 void disarm() { mDevice = nullptr; }
318
319 private:
320 DeviceHalAidl* mDevice;
321 const Cleaner mCleaner;
322 const int32_t mId;
323};
324
325} // namespace
326
327// Since the order of container elements destruction is unspecified,
328// ensure that cleanups are performed from the most recent one and upwards.
329// This is the same as if there were individual Cleanup instances on the stack,
330// however the bonus is that we can disarm all of them with just one statement.
331class DeviceHalAidl::Cleanups : public std::forward_list<Cleanup> {
332 public:
333 ~Cleanups() { for (auto& c : *this) c.clean(); }
334 void disarmAll() { for (auto& c : *this) c.disarm(); }
335};
336
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800337status_t DeviceHalAidl::getInputBufferSize(const struct audio_config* config, size_t* size) {
338 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
339 if (size == nullptr) return BAD_VALUE;
340 TIME_CHECK();
341 if (!mModule) return NO_INIT;
342 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
343 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
344 AudioDevice aidlDevice;
345 aidlDevice.type.type = AudioDeviceType::IN_DEFAULT;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800346 AudioSource aidlSource = AudioSource::DEFAULT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800347 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
348 AudioPortConfig mixPortConfig;
349 Cleanups cleanups;
350 audio_config writableConfig = *config;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700351 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800352 RETURN_STATUS_IF_ERROR(prepareToOpenStream(0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700353 &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800354 *size = aidlConfig.frameCount *
355 getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
356 // Do not disarm cleanups to release temporary port configs.
357 return OK;
358}
359
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800360status_t DeviceHalAidl::prepareToOpenStream(
361 int32_t aidlHandle, const AudioDevice& aidlDevice, const AudioIoFlags& aidlFlags,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800362 AudioSource aidlSource, struct audio_config* config,
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800363 Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700364 AudioPatch* aidlPatch) {
365 ALOGD("%p %s::%s: handle %d, device %s, flags %s, source %s, config %s, mix port config %s",
366 this, getClassName().c_str(), __func__, aidlHandle, aidlDevice.toString().c_str(),
367 aidlFlags.toString().c_str(), toString(aidlSource).c_str(),
368 aidlConfig->toString().c_str(), mixPortConfig->toString().c_str());
jiabin9c07faf2023-04-26 22:00:44 +0000369 resetUnusedPatchesAndPortConfigs();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800370 const bool isInput = aidlFlags.getTag() == AudioIoFlags::Tag::input;
371 // Find / create AudioPortConfigs for the device port and the mix port,
372 // then find / create a patch between them, and open a stream on the mix port.
373 AudioPortConfig devicePortConfig;
374 bool created = false;
jiabin9c07faf2023-04-26 22:00:44 +0000375 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, aidlConfig,
376 &devicePortConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800377 if (created) {
378 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
379 }
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800380 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*aidlConfig, aidlFlags, aidlHandle, aidlSource,
Mikhail Naganov289468a2023-03-29 10:06:15 -0700381 std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800382 if (created) {
383 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
384 }
385 setConfigFromPortConfig(aidlConfig, *mixPortConfig);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800386 if (isInput) {
387 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700388 {devicePortConfig.id}, {mixPortConfig->id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800389 } else {
390 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700391 {mixPortConfig->id}, {devicePortConfig.id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800392 }
393 if (created) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700394 cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, aidlPatch->id);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800395 }
396 if (aidlConfig->frameCount <= 0) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700397 aidlConfig->frameCount = aidlPatch->minimumStreamBufferSizeFrames;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800398 }
399 *config = VALUE_OR_RETURN_STATUS(
400 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(*aidlConfig, isInput));
401 return OK;
402}
403
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800404namespace {
405
406class StreamCallbackBase {
407 protected:
408 explicit StreamCallbackBase(const sp<CallbackBroker>& broker) : mBroker(broker) {}
409 public:
410 void* getCookie() const { return mCookie; }
411 void setCookie(void* cookie) { mCookie = cookie; }
412 sp<CallbackBroker> getBroker() const {
413 if (void* cookie = mCookie; cookie != nullptr) return mBroker.promote();
414 return nullptr;
415 }
416 private:
417 const wp<CallbackBroker> mBroker;
418 std::atomic<void*> mCookie;
419};
420
421template<class C>
422class StreamCallbackBaseHelper {
423 protected:
424 explicit StreamCallbackBaseHelper(const StreamCallbackBase& base) : mBase(base) {}
425 sp<C> getCb(const sp<CallbackBroker>& broker, void* cookie);
426 using CbRef = const sp<C>&;
427 ndk::ScopedAStatus runCb(const std::function<void(CbRef cb)>& f) {
428 if (auto cb = getCb(mBase.getBroker(), mBase.getCookie()); cb != nullptr) f(cb);
429 return ndk::ScopedAStatus::ok();
430 }
431 private:
432 const StreamCallbackBase& mBase;
433};
434
435template<>
436sp<StreamOutHalInterfaceCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>::getCb(
437 const sp<CallbackBroker>& broker, void* cookie) {
438 if (broker != nullptr) return broker->getStreamOutCallback(cookie);
439 return nullptr;
440}
441
442template<>
443sp<StreamOutHalInterfaceEventCallback>
444StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::getCb(
445 const sp<CallbackBroker>& broker, void* cookie) {
446 if (broker != nullptr) return broker->getStreamOutEventCallback(cookie);
447 return nullptr;
448}
449
450template<>
451sp<StreamOutHalInterfaceLatencyModeCallback>
452StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::getCb(
453 const sp<CallbackBroker>& broker, void* cookie) {
454 if (broker != nullptr) return broker->getStreamOutLatencyModeCallback(cookie);
455 return nullptr;
456}
457
458/*
459Note on the callback ownership.
460
461In the Binder ownership model, the server implementation is kept alive
462as long as there is any client (proxy object) alive. This is done by
463incrementing the refcount of the server-side object by the Binder framework.
464When it detects that the last client is gone, it decrements the refcount back.
465
466Thus, it is not needed to keep any references to StreamCallback on our
467side (after we have sent an instance to the client), because we are
468the server-side. The callback object will be kept alive as long as the HAL server
469holds a strong ref to IStreamCallback proxy.
470*/
471
472class OutputStreamCallbackAidl : public StreamCallbackBase,
473 public StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>,
474 public ::aidl::android::hardware::audio::core::BnStreamCallback {
475 public:
476 explicit OutputStreamCallbackAidl(const sp<CallbackBroker>& broker)
477 : StreamCallbackBase(broker),
478 StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>(
479 *static_cast<StreamCallbackBase*>(this)) {}
480 ndk::ScopedAStatus onTransferReady() override {
481 return runCb([](CbRef cb) { cb->onWriteReady(); });
482 }
483 ndk::ScopedAStatus onError() override {
484 return runCb([](CbRef cb) { cb->onError(); });
485 }
486 ndk::ScopedAStatus onDrainReady() override {
487 return runCb([](CbRef cb) { cb->onDrainReady(); });
488 }
489};
490
491class OutputStreamEventCallbackAidl :
492 public StreamCallbackBase,
493 public StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>,
494 public StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>,
495 public ::aidl::android::hardware::audio::core::BnStreamOutEventCallback {
496 public:
497 explicit OutputStreamEventCallbackAidl(const sp<CallbackBroker>& broker)
498 : StreamCallbackBase(broker),
499 StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>(
500 *static_cast<StreamCallbackBase*>(this)),
501 StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>(
502 *static_cast<StreamCallbackBase*>(this)) {}
503 ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& in_audioMetadata) override {
504 std::basic_string<uint8_t> halMetadata(in_audioMetadata.begin(), in_audioMetadata.end());
505 return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb(
506 [&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); });
507 }
508 ndk::ScopedAStatus onRecommendedLatencyModeChanged(
509 const std::vector<AudioLatencyMode>& in_modes) override {
510 auto halModes = VALUE_OR_FATAL(
511 ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
512 in_modes,
513 ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
514 return StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::runCb(
515 [&halModes](auto cb) { cb->onRecommendedLatencyModeChanged(halModes); });
516 }
517};
518
519} // namespace
520
Mikhail Naganov31d46652023-01-10 18:29:25 +0000521status_t DeviceHalAidl::openOutputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800522 audio_io_handle_t handle, audio_devices_t devices,
523 audio_output_flags_t flags, struct audio_config* config,
524 const char* address,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000525 sp<StreamOutHalInterface>* outStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800526 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000527 if (!outStream || !config) {
528 return BAD_VALUE;
529 }
530 TIME_CHECK();
531 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800532 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
533 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
534 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
535 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, false /*isInput*/));
536 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
537 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
538 int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
539 ::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
540 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
541 AudioPortConfig mixPortConfig;
542 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700543 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800544 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
545 AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700546 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800547 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
548 args.portConfigId = mixPortConfig.id;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800549 const bool isOffload = isBitPositionFlagSet(
550 aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD);
551 std::shared_ptr<OutputStreamCallbackAidl> streamCb;
552 if (isOffload) {
553 streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
554 }
555 auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
556 if (isOffload) {
557 args.offloadInfo = aidlConfig.offloadInfo;
558 args.callback = streamCb;
559 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800560 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800561 args.eventCallback = eventCb;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800562 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
563 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800564 StreamContextAidl context(ret.desc, isOffload);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800565 if (!context.isValid()) {
566 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
567 __func__, ret.desc.toString().c_str());
568 return NO_INIT;
569 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700570 *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800571 std::move(ret.stream), this /*callbackBroker*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700572 mStreams.insert(std::pair(*outStream, aidlPatch.id));
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800573 void* cbCookie = (*outStream).get();
574 {
575 std::lock_guard l(mLock);
576 mCallbacks.emplace(cbCookie, Callbacks{});
577 }
578 if (streamCb) streamCb->setCookie(cbCookie);
579 eventCb->setCookie(cbCookie);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800580 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000581 return OK;
582}
583
Mikhail Naganov31d46652023-01-10 18:29:25 +0000584status_t DeviceHalAidl::openInputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800585 audio_io_handle_t handle, audio_devices_t devices,
586 struct audio_config* config, audio_input_flags_t flags,
587 const char* address, audio_source_t source,
588 audio_devices_t outputDevice, const char* outputDeviceAddress,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000589 sp<StreamInHalInterface>* inStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800590 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000591 if (!inStream || !config) {
592 return BAD_VALUE;
593 }
594 TIME_CHECK();
595 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800596 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
597 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
598 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
599 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
600 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
601 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
602 int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
603 ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
604 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
605 AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
606 ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
607 AudioPortConfig mixPortConfig;
608 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700609 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800610 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700611 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800612 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
613 args.portConfigId = mixPortConfig.id;
614 RecordTrackMetadata aidlTrackMetadata{
615 .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
616 if (outputDevice != AUDIO_DEVICE_NONE) {
617 aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
618 ::aidl::android::legacy2aidl_audio_device_AudioDevice(
619 outputDevice, outputDeviceAddress));
620 }
621 args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
622 args.bufferSizeFrames = aidlConfig.frameCount;
623 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
624 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800625 StreamContextAidl context(ret.desc, false /*isAsynchronous*/);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800626 if (!context.isValid()) {
627 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
628 __func__, ret.desc.toString().c_str());
629 return NO_INIT;
630 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700631 *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800632 std::move(ret.stream), this /*micInfoProvider*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700633 mStreams.insert(std::pair(*inStream, aidlPatch.id));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800634 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000635 return OK;
636}
637
638status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
639 *supportsPatches = true;
640 return OK;
641}
642
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800643status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
644 const struct audio_port_config* sources,
645 unsigned int num_sinks,
646 const struct audio_port_config* sinks,
647 audio_patch_handle_t* patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800648 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000649 TIME_CHECK();
650 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800651 if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
652 sources == nullptr || sinks == nullptr || patch == nullptr) {
653 return BAD_VALUE;
654 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800655 // When the patch handle (*patch) is AUDIO_PATCH_HANDLE_NONE, it means
656 // the framework wants to create a new patch. The handle has to be generated
657 // by the HAL. Since handles generated this way can only be unique within
658 // a HAL module, the framework generates a globally unique handle, and maps
659 // it on the <HAL module, patch handle> pair.
660 // When the patch handle is set, it meant the framework intends to update
661 // an existing patch.
662 //
663 // This behavior corresponds to HAL module behavior, with the only difference
664 // that the HAL module uses `int32_t` for patch IDs. The following assert ensures
665 // that both the framework and the HAL use the same value for "no ID":
666 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
667 int32_t halPatchId = static_cast<int32_t>(*patch);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800668
669 // Upon conversion, mix port configs contain audio configuration, while
670 // device port configs contain device address. This data is used to find
671 // or create HAL configs.
672 std::vector<AudioPortConfig> aidlSources, aidlSinks;
673 for (unsigned int i = 0; i < num_sources; ++i) {
674 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
675 sources[i].role, sources[i].type)) ==
676 ::aidl::android::AudioPortDirection::INPUT;
677 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
678 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
679 sources[i], isInput, 0)));
680 }
681 for (unsigned int i = 0; i < num_sinks; ++i) {
682 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
683 sinks[i].role, sinks[i].type)) ==
684 ::aidl::android::AudioPortDirection::INPUT;
685 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
686 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
687 sinks[i], isInput, 0)));
688 }
689 Cleanups cleanups;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800690 auto existingPatchIt = halPatchId != 0 ? mPatches.find(halPatchId): mPatches.end();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800691 AudioPatch aidlPatch;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800692 if (existingPatchIt != mPatches.end()) {
693 aidlPatch = existingPatchIt->second;
694 aidlPatch.sourcePortConfigIds.clear();
695 aidlPatch.sinkPortConfigIds.clear();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800696 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800697 ALOGD("%s: sources: %s, sinks: %s",
698 __func__, ::android::internal::ToString(aidlSources).c_str(),
699 ::android::internal::ToString(aidlSinks).c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800700 auto fillPortConfigs = [&](
Mikhail Naganov289468a2023-03-29 10:06:15 -0700701 const std::vector<AudioPortConfig>& configs,
702 const std::set<int32_t>& destinationPortIds,
703 std::vector<int32_t>* ids, std::set<int32_t>* portIds) -> status_t {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800704 for (const auto& s : configs) {
705 AudioPortConfig portConfig;
706 bool created = false;
Mikhail Naganov289468a2023-03-29 10:06:15 -0700707 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
708 s, destinationPortIds, &portConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800709 if (created) {
710 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, portConfig.id);
711 }
712 ids->push_back(portConfig.id);
Mikhail Naganov289468a2023-03-29 10:06:15 -0700713 if (portIds != nullptr) {
714 portIds->insert(portConfig.portId);
715 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800716 }
717 return OK;
718 };
Mikhail Naganov289468a2023-03-29 10:06:15 -0700719 // When looking up port configs, the destinationPortId is only used for mix ports.
720 // Thus, we process device port configs first, and look up the destination port ID from them.
721 bool sourceIsDevice = std::any_of(aidlSources.begin(), aidlSources.end(),
722 [](const auto& config) { return config.ext.getTag() == AudioPortExt::device; });
723 const std::vector<AudioPortConfig>& devicePortConfigs =
724 sourceIsDevice ? aidlSources : aidlSinks;
725 std::vector<int32_t>* devicePortConfigIds =
726 sourceIsDevice ? &aidlPatch.sourcePortConfigIds : &aidlPatch.sinkPortConfigIds;
727 const std::vector<AudioPortConfig>& mixPortConfigs =
728 sourceIsDevice ? aidlSinks : aidlSources;
729 std::vector<int32_t>* mixPortConfigIds =
730 sourceIsDevice ? &aidlPatch.sinkPortConfigIds : &aidlPatch.sourcePortConfigIds;
731 std::set<int32_t> devicePortIds;
732 RETURN_STATUS_IF_ERROR(fillPortConfigs(
733 devicePortConfigs, std::set<int32_t>(), devicePortConfigIds, &devicePortIds));
734 RETURN_STATUS_IF_ERROR(fillPortConfigs(
735 mixPortConfigs, devicePortIds, mixPortConfigIds, nullptr));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800736 if (existingPatchIt != mPatches.end()) {
737 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
738 mModule->setAudioPatch(aidlPatch, &aidlPatch)));
739 existingPatchIt->second = aidlPatch;
740 } else {
741 bool created = false;
742 RETURN_STATUS_IF_ERROR(findOrCreatePatch(aidlPatch, &aidlPatch, &created));
743 // Since no cleanup of the patch is needed, 'created' is ignored.
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800744 halPatchId = aidlPatch.id;
745 *patch = static_cast<audio_patch_handle_t>(halPatchId);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800746 }
747 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000748 return OK;
749}
750
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800751status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800752 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000753 TIME_CHECK();
754 if (!mModule) return NO_INIT;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800755 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
756 if (patch == AUDIO_PATCH_HANDLE_NONE) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800757 return BAD_VALUE;
758 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800759 int32_t halPatchId = static_cast<int32_t>(patch);
760 auto patchIt = mPatches.find(halPatchId);
761 if (patchIt == mPatches.end()) {
762 ALOGE("%s: patch with id %d not found", __func__, halPatchId);
763 return BAD_VALUE;
764 }
765 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->resetAudioPatch(halPatchId)));
766 mPatches.erase(patchIt);
Shunkai Yao51202502022-12-12 06:11:46 +0000767 return OK;
768}
769
Mikhail Naganove93a0862023-03-15 17:06:59 -0700770status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
771 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000772 TIME_CHECK();
773 if (!mModule) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700774 if (port == nullptr) {
775 return BAD_VALUE;
776 }
777 audio_port_v7 portV7;
778 audio_populate_audio_port_v7(port, &portV7);
779 RETURN_STATUS_IF_ERROR(getAudioPort(&portV7));
780 return audio_populate_audio_port(&portV7, port) ? OK : BAD_VALUE;
781}
782
783status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
784 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
785 TIME_CHECK();
786 if (!mModule) return NO_INIT;
787 if (port == nullptr) {
788 return BAD_VALUE;
789 }
790 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
791 ::aidl::android::AudioPortDirection::INPUT;
792 auto aidlPort = VALUE_OR_RETURN_STATUS(
793 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
794 if (aidlPort.ext.getTag() != AudioPortExt::device) {
795 ALOGE("%s: provided port is not a device port (module %s): %s",
796 __func__, mInstance.c_str(), aidlPort.toString().c_str());
797 return BAD_VALUE;
798 }
799 const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
800 // It seems that we don't have to call HAL since all valid ports have been added either
801 // during initialization, or while handling connection of an external device.
802 auto portsIt = findPort(matchDevice);
803 if (portsIt == mPorts.end()) {
804 ALOGE("%s: device port for device %s is not found in the module %s",
805 __func__, matchDevice.toString().c_str(), mInstance.c_str());
806 return BAD_VALUE;
807 }
808 const int32_t fwkId = aidlPort.id;
809 aidlPort = portsIt->second;
810 aidlPort.id = fwkId;
811 *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
812 aidlPort, isInput));
813 return OK;
814}
815
816status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
817 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
818 TIME_CHECK();
819 if (!mModule) return NO_INIT;
820 if (config == nullptr) {
821 return BAD_VALUE;
822 }
823 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
824 config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
825 AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
826 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
827 *config, isInput, 0 /*portId*/));
828 AudioPortConfig portConfig;
829 bool created = false;
Mikhail Naganov289468a2023-03-29 10:06:15 -0700830 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
831 requestedPortConfig, std::set<int32_t>(), &portConfig, &created));
Shunkai Yao51202502022-12-12 06:11:46 +0000832 return OK;
833}
834
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800835MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
836 if (mMicrophones.status == Microphones::Status::UNKNOWN) {
837 TIME_CHECK();
838 std::vector<MicrophoneInfo> aidlInfo;
839 status_t status = statusTFromBinderStatus(mModule->getMicrophones(&aidlInfo));
840 if (status == OK) {
841 mMicrophones.status = Microphones::Status::QUERIED;
842 mMicrophones.info = std::move(aidlInfo);
843 } else if (status == INVALID_OPERATION) {
844 mMicrophones.status = Microphones::Status::NOT_SUPPORTED;
845 } else {
846 ALOGE("%s: Unexpected status from 'IModule.getMicrophones': %d", __func__, status);
847 return {};
848 }
849 }
850 if (mMicrophones.status == Microphones::Status::QUERIED) {
851 return &mMicrophones.info;
852 }
853 return {}; // NOT_SUPPORTED
854}
855
Shunkai Yao51202502022-12-12 06:11:46 +0000856status_t DeviceHalAidl::getMicrophones(
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800857 std::vector<audio_microphone_characteristic_t>* microphones) {
858 if (!microphones) {
859 return BAD_VALUE;
860 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000861 TIME_CHECK();
862 if (!mModule) return NO_INIT;
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800863 auto staticInfo = getMicrophoneInfo();
864 if (!staticInfo) return INVALID_OPERATION;
865 std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
866 emptyDynamicInfo.reserve(staticInfo->size());
867 std::transform(staticInfo->begin(), staticInfo->end(), std::back_inserter(emptyDynamicInfo),
868 [](const auto& info) { return MicrophoneDynamicInfo{ .id = info.id }; });
869 *microphones = VALUE_OR_RETURN_STATUS(
870 ::aidl::android::convertContainers<std::vector<audio_microphone_characteristic_t>>(
871 *staticInfo, emptyDynamicInfo,
872 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t)
873 );
Shunkai Yao51202502022-12-12 06:11:46 +0000874 return OK;
875}
876
Mikhail Naganov31d46652023-01-10 18:29:25 +0000877status_t DeviceHalAidl::addDeviceEffect(audio_port_handle_t device __unused,
878 sp<EffectHalInterface> effect) {
Shunkai Yao51202502022-12-12 06:11:46 +0000879 if (!effect) {
880 return BAD_VALUE;
881 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000882 TIME_CHECK();
883 if (!mModule) return NO_INIT;
884 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000885 return OK;
886}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000887status_t DeviceHalAidl::removeDeviceEffect(audio_port_handle_t device __unused,
Shunkai Yao51202502022-12-12 06:11:46 +0000888 sp<EffectHalInterface> effect) {
889 if (!effect) {
890 return BAD_VALUE;
891 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000892 TIME_CHECK();
893 if (!mModule) return NO_INIT;
894 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000895 return OK;
896}
897
898status_t DeviceHalAidl::getMmapPolicyInfos(
David Li9cf5e622023-03-21 00:51:10 +0800899 media::audio::common::AudioMMapPolicyType policyType,
900 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000901 TIME_CHECK();
Mikhail Naganov25bc9a22023-04-21 18:48:16 -0700902 AudioMMapPolicyType mmapPolicyType = VALUE_OR_RETURN_STATUS(
903 cpp2ndk_AudioMMapPolicyType(policyType));
David Li9cf5e622023-03-21 00:51:10 +0800904
905 std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
906
907 if (status_t status = statusTFromBinderStatus(
908 mModule->getMmapPolicyInfos(mmapPolicyType, &mmapPolicyInfos)); status != OK) {
909 return status;
910 }
911
912 *policyInfos = VALUE_OR_RETURN_STATUS(
913 convertContainer<std::vector<media::audio::common::AudioMMapPolicyInfo>>(
914 mmapPolicyInfos, ndk2cpp_AudioMMapPolicyInfo));
Shunkai Yao51202502022-12-12 06:11:46 +0000915 return OK;
916}
917
918int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000919 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800920 int32_t mixerBurstCount = 0;
921 if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
922 return mixerBurstCount;
923 }
924 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000925}
926
927int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000928 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800929 int32_t hardwareBurstMinUsec = 0;
930 if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
931 return hardwareBurstMinUsec;
932 }
933 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000934}
935
936error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000937 TIME_CHECK();
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700938 if (!mModule) return NO_INIT;
939 int32_t aidlHwAvSync;
940 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
941 return VALUE_OR_RETURN_STATUS(
942 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +0000943}
944
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000945status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
946 TIME_CHECK();
947 if (!mModule) return NO_INIT;
948 return mModule->dump(fd, Args(args).args(), args.size());
David Li9cf5e622023-03-21 00:51:10 +0800949}
Shunkai Yao51202502022-12-12 06:11:46 +0000950
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700951int32_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000952 TIME_CHECK();
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700953 if (!mModule) return NO_INIT;
954 if (supports == nullptr) {
955 return BAD_VALUE;
956 }
957 return statusTFromBinderStatus(mModule->supportsVariableLatency(supports));
Shunkai Yao51202502022-12-12 06:11:46 +0000958}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000959
jiabin872de702023-04-27 22:04:31 +0000960
961status_t DeviceHalAidl::prepareToDisconnectExternalDevice(const struct audio_port_v7* port) {
962 // There is not AIDL API defined for `prepareToDisconnectExternalDevice`.
963 // Call `setConnectedState` instead.
964 // TODO(b/279824103): call prepareToDisconnectExternalDevice when it is added.
965 const status_t status = setConnectedState(port, false /*connected*/);
966 if (status == NO_ERROR) {
967 mDeviceDisconnectionNotified.insert(port->id);
968 }
969 return status;
970}
971
Mikhail Naganove93a0862023-03-15 17:06:59 -0700972status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
973 TIME_CHECK();
974 if (!mModule) return NO_INIT;
975 if (port == nullptr) {
976 return BAD_VALUE;
977 }
jiabin872de702023-04-27 22:04:31 +0000978 if (!connected && mDeviceDisconnectionNotified.erase(port->id) > 0) {
979 // For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
980 // and then call `setConnectedState`. However, there is no API for
981 // `prepareToDisconnectExternalDevice` yet. In that case, `setConnectedState` will be
982 // called when calling `prepareToDisconnectExternalDevice`. Do not call to the HAL if
983 // previous call is successful. Also remove the cache here to avoid a large cache after
984 // a long run.
985 return NO_ERROR;
986 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700987 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
988 ::aidl::android::AudioPortDirection::INPUT;
989 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
990 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
991 if (aidlPort.ext.getTag() != AudioPortExt::device) {
992 ALOGE("%s: provided port is not a device port (module %s): %s",
993 __func__, mInstance.c_str(), aidlPort.toString().c_str());
994 return BAD_VALUE;
995 }
996 if (connected) {
997 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
998 // Reset the device address to find the "template" port.
999 matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
1000 auto portsIt = findPort(matchDevice);
1001 if (portsIt == mPorts.end()) {
1002 ALOGW("%s: device port for device %s is not found in the module %s",
1003 __func__, matchDevice.toString().c_str(), mInstance.c_str());
1004 return BAD_VALUE;
1005 }
1006 // Use the ID of the "template" port, use all the information from the provided port.
1007 aidlPort.id = portsIt->first;
1008 AudioPort connectedPort;
1009 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
1010 aidlPort, &connectedPort)));
1011 const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
1012 LOG_ALWAYS_FATAL_IF(!inserted,
1013 "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
1014 __func__, mInstance.c_str(), connectedPort.toString().c_str(),
1015 it->second.toString().c_str());
1016 } else { // !connected
1017 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1018 auto portsIt = findPort(matchDevice);
1019 if (portsIt == mPorts.end()) {
1020 ALOGW("%s: device port for device %s is not found in the module %s",
1021 __func__, matchDevice.toString().c_str(), mInstance.c_str());
1022 return BAD_VALUE;
1023 }
1024 // Any streams opened on the external device must be closed by this time,
1025 // thus we can clean up patches and port configs that were created for them.
1026 resetUnusedPatchesAndPortConfigs();
1027 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
1028 portsIt->second.id)));
1029 mPorts.erase(portsIt);
1030 }
Mikhail Naganov289468a2023-03-29 10:06:15 -07001031 return updateRoutes();
Mikhail Naganove93a0862023-03-15 17:06:59 -07001032}
1033
1034status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
1035 TIME_CHECK();
1036 if (!mModule) return NO_INIT;
1037 ModuleDebug debug{ .simulateDeviceConnections = enabled };
1038 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
1039 // This is important to log as it affects HAL behavior.
1040 if (status == OK) {
1041 ALOGI("%s: set enabled: %d", __func__, enabled);
1042 } else {
1043 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
1044 }
1045 return status;
1046}
1047
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001048bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
1049 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1050 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1051}
1052
1053bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
1054 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1055 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1056 return p.portId == mDefaultInputPortId;
1057 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1058 return p.portId == mDefaultOutputPortId;
1059 }
1060 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1061}
1062
David Lia8675d42023-03-30 21:08:06 +08001063status_t DeviceHalAidl::createOrUpdatePortConfig(
1064 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool* created) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001065 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001066 AudioPortConfig appliedPortConfig;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001067 bool applied = false;
1068 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001069 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001070 if (!applied) {
1071 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001072 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001073 if (!applied) {
1074 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001075 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001076 return NO_INIT;
1077 }
1078 }
David Lia8675d42023-03-30 21:08:06 +08001079
1080 int32_t id = appliedPortConfig.id;
1081 if (requestedPortConfig.id != 0 && requestedPortConfig.id != id) {
1082 LOG_ALWAYS_FATAL("%s: requested port config id %d changed to %d", __func__,
1083 requestedPortConfig.id, id);
1084 }
1085
1086 auto [it, inserted] = mPortConfigs.insert_or_assign(std::move(id),
1087 std::move(appliedPortConfig));
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001088 *result = it;
David Lia8675d42023-03-30 21:08:06 +08001089 *created = inserted;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001090 return OK;
1091}
1092
Mikhail Naganovccc82112023-04-27 18:14:15 -07001093status_t DeviceHalAidl::filterAndUpdateBtA2dpParameters(AudioParameter &parameters) {
1094 TIME_CHECK();
1095 std::optional<bool> a2dpEnabled;
1096 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1097 parameters, String8(AudioParameter::keyBtA2dpSuspended),
1098 [&a2dpEnabled](const String8& trueOrFalse) {
1099 if (trueOrFalse == AudioParameter::valueTrue) {
1100 a2dpEnabled = false; // 'suspended' == true
1101 return OK;
1102 } else if (trueOrFalse == AudioParameter::valueFalse) {
1103 a2dpEnabled = true; // 'suspended' == false
1104 return OK;
1105 }
1106 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1107 AudioParameter::keyBtA2dpSuspended, trueOrFalse.c_str());
1108 return BAD_VALUE;
1109 }));
1110 // FIXME(b/278976019): Support keyReconfigA2dp via vendor plugin
1111 if (mBluetoothA2dp != nullptr && a2dpEnabled.has_value()) {
1112 return statusTFromBinderStatus(mBluetoothA2dp->setEnabled(a2dpEnabled.value()));
1113 }
1114 return OK;
1115}
1116
1117status_t DeviceHalAidl::filterAndUpdateBtHfpParameters(AudioParameter &parameters) {
1118 TIME_CHECK();
1119 IBluetooth::HfpConfig hfpConfig;
1120 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1121 parameters, String8(AudioParameter::keyBtHfpEnable),
1122 [&hfpConfig](const String8& trueOrFalse) {
1123 if (trueOrFalse == AudioParameter::valueTrue) {
1124 hfpConfig.isEnabled = Boolean{ .value = true };
1125 return OK;
1126 } else if (trueOrFalse == AudioParameter::valueFalse) {
1127 hfpConfig.isEnabled = Boolean{ .value = false };
1128 return OK;
1129 }
1130 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1131 AudioParameter::keyBtHfpEnable, trueOrFalse.c_str());
1132 return BAD_VALUE;
1133 }));
1134 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1135 parameters, String8(AudioParameter::keyBtHfpSamplingRate),
1136 [&hfpConfig](int sampleRate) {
1137 return sampleRate > 0 ?
1138 hfpConfig.sampleRate = Int{ .value = sampleRate }, OK : BAD_VALUE;
1139 }));
1140 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1141 parameters, String8(AudioParameter::keyBtHfpVolume),
1142 [&hfpConfig](int volume0to15) {
1143 if (volume0to15 >= 0 && volume0to15 <= 15) {
1144 hfpConfig.volume = Float{ .value = volume0to15 / 15.0f };
1145 return OK;
1146 }
1147 return BAD_VALUE;
1148 }));
1149 if (mBluetooth != nullptr && hfpConfig != IBluetooth::HfpConfig{}) {
1150 IBluetooth::HfpConfig newHfpConfig;
1151 return statusTFromBinderStatus(mBluetooth->setHfpConfig(hfpConfig, &newHfpConfig));
1152 }
1153 return OK;
1154}
1155
1156status_t DeviceHalAidl::filterAndUpdateBtLeParameters(AudioParameter &parameters) {
1157 TIME_CHECK();
1158 std::optional<bool> leEnabled;
1159 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1160 parameters, String8(AudioParameter::keyBtLeSuspended),
1161 [&leEnabled](const String8& trueOrFalse) {
1162 if (trueOrFalse == AudioParameter::valueTrue) {
1163 leEnabled = false; // 'suspended' == true
1164 return OK;
1165 } else if (trueOrFalse == AudioParameter::valueFalse) {
1166 leEnabled = true; // 'suspended' == false
1167 return OK;
1168 }
1169 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1170 AudioParameter::keyBtLeSuspended, trueOrFalse.c_str());
1171 return BAD_VALUE;
1172 }));
1173 if (mBluetoothLe != nullptr && leEnabled.has_value()) {
1174 return statusTFromBinderStatus(mBluetoothLe->setEnabled(leEnabled.value()));
1175 }
1176 return OK;
1177}
1178
1179status_t DeviceHalAidl::filterAndUpdateBtScoParameters(AudioParameter &parameters) {
1180 TIME_CHECK();
1181 IBluetooth::ScoConfig scoConfig;
1182 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1183 parameters, String8(AudioParameter::keyBtSco),
1184 [&scoConfig](const String8& onOrOff) {
1185 if (onOrOff == AudioParameter::valueOn) {
1186 scoConfig.isEnabled = Boolean{ .value = true };
1187 return OK;
1188 } else if (onOrOff == AudioParameter::valueOff) {
1189 scoConfig.isEnabled = Boolean{ .value = false };
1190 return OK;
1191 }
1192 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1193 AudioParameter::keyBtSco, onOrOff.c_str());
1194 return BAD_VALUE;
1195 }));
1196 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1197 parameters, String8(AudioParameter::keyBtScoHeadsetName),
1198 [&scoConfig](const String8& name) {
1199 scoConfig.debugName = name;
1200 return OK;
1201 }));
1202 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1203 parameters, String8(AudioParameter::keyBtNrec),
1204 [&scoConfig](const String8& onOrOff) {
1205 if (onOrOff == AudioParameter::valueOn) {
1206 scoConfig.isNrecEnabled = Boolean{ .value = true };
1207 return OK;
1208 } else if (onOrOff == AudioParameter::valueOff) {
1209 scoConfig.isNrecEnabled = Boolean{ .value = false };
1210 return OK;
1211 }
1212 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1213 AudioParameter::keyBtNrec, onOrOff.c_str());
1214 return BAD_VALUE;
1215 }));
1216 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1217 parameters, String8(AudioParameter::keyBtScoWb),
1218 [&scoConfig](const String8& onOrOff) {
1219 if (onOrOff == AudioParameter::valueOn) {
1220 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO_WB;
1221 return OK;
1222 } else if (onOrOff == AudioParameter::valueOff) {
1223 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO;
1224 return OK;
1225 }
1226 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1227 AudioParameter::keyBtScoWb, onOrOff.c_str());
1228 return BAD_VALUE;
1229 }));
1230 if (mBluetooth != nullptr && scoConfig != IBluetooth::ScoConfig{}) {
1231 IBluetooth::ScoConfig newScoConfig;
1232 return statusTFromBinderStatus(mBluetooth->setScoConfig(scoConfig, &newScoConfig));
1233 }
1234 return OK;
1235}
1236
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001237status_t DeviceHalAidl::findOrCreatePatch(
1238 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
1239 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
1240 requestedPatch.sourcePortConfigIds.end());
1241 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
1242 requestedPatch.sinkPortConfigIds.end());
1243 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
1244}
1245
1246status_t DeviceHalAidl::findOrCreatePatch(
1247 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
1248 AudioPatch* patch, bool* created) {
1249 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
1250 if (patchIt == mPatches.end()) {
1251 TIME_CHECK();
1252 AudioPatch requestedPatch, appliedPatch;
1253 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
1254 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
1255 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
1256 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
1257 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
1258 requestedPatch, &appliedPatch)));
1259 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
1260 *created = true;
1261 } else {
1262 *created = false;
1263 }
1264 *patch = patchIt->second;
1265 return OK;
1266}
1267
jiabin9c07faf2023-04-26 22:00:44 +00001268status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device, const AudioConfig* config,
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001269 AudioPortConfig* portConfig, bool* created) {
1270 auto portConfigIt = findPortConfig(device);
1271 if (portConfigIt == mPortConfigs.end()) {
1272 auto portsIt = findPort(device);
1273 if (portsIt == mPorts.end()) {
1274 ALOGE("%s: device port for device %s is not found in the module %s",
1275 __func__, device.toString().c_str(), mInstance.c_str());
1276 return BAD_VALUE;
1277 }
1278 AudioPortConfig requestedPortConfig;
1279 requestedPortConfig.portId = portsIt->first;
jiabin9c07faf2023-04-26 22:00:44 +00001280 if (config != nullptr) {
1281 setPortConfigFromConfig(&requestedPortConfig, *config);
1282 }
David Lia8675d42023-03-30 21:08:06 +08001283 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1284 created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001285 } else {
1286 *created = false;
1287 }
1288 *portConfig = portConfigIt->second;
1289 return OK;
1290}
1291
1292status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001293 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001294 AudioSource source, const std::set<int32_t>& destinationPortIds,
1295 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001296 // These flags get removed one by one in this order when retrying port finding.
1297 static const std::vector<AudioInputFlags> kOptionalInputFlags{
1298 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001299 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001300 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001301 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
1302 AudioIoFlags matchFlags = flags.value();
Mikhail Naganov289468a2023-03-29 10:06:15 -07001303 auto portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001304 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
1305 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
1306 if (!isBitPositionFlagSet(
1307 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
1308 ++optionalInputFlagsIt;
1309 continue;
1310 }
1311 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
1312 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
Mikhail Naganov289468a2023-03-29 10:06:15 -07001313 portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001314 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
1315 "retried with flags %s", __func__, config.toString().c_str(),
1316 flags.value().toString().c_str(), mInstance.c_str(),
1317 matchFlags.toString().c_str());
1318 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001319 if (portsIt == mPorts.end()) {
1320 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001321 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001322 mInstance.c_str());
1323 return BAD_VALUE;
1324 }
1325 AudioPortConfig requestedPortConfig;
1326 requestedPortConfig.portId = portsIt->first;
1327 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001328 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001329 if (matchFlags.getTag() == AudioIoFlags::Tag::input
1330 && source != AudioSource::SYS_RESERVED_INVALID) {
1331 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
1332 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
1333 }
David Lia8675d42023-03-30 21:08:06 +08001334 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1335 created));
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001336 } else if (!flags.has_value()) {
1337 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
1338 "and was not created as flags are not specified",
1339 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
1340 return BAD_VALUE;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001341 } else {
David Lia8675d42023-03-30 21:08:06 +08001342 AudioPortConfig requestedPortConfig = portConfigIt->second;
1343 if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
1344 AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
1345 if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
1346 source != AudioSource::SYS_RESERVED_INVALID) {
1347 mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
1348 }
1349 }
1350
1351 if (requestedPortConfig != portConfigIt->second) {
1352 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1353 created));
1354 } else {
1355 *created = false;
1356 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001357 }
1358 *portConfig = portConfigIt->second;
1359 return OK;
1360}
1361
1362status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001363 const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
1364 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001365 using Tag = AudioPortExt::Tag;
1366 if (requestedPortConfig.ext.getTag() == Tag::mix) {
1367 if (const auto& p = requestedPortConfig;
1368 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001369 !p.format.has_value()) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001370 ALOGW("%s: provided mix port config is not fully specified: %s",
1371 __func__, p.toString().c_str());
1372 return BAD_VALUE;
1373 }
1374 AudioConfig config;
1375 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001376 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
1377 AudioPortMixExtUseCase::Tag::source ?
1378 requestedPortConfig.ext.get<Tag::mix>().usecase.
1379 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001380 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001381 requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
1382 portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001383 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
1384 return findOrCreatePortConfig(
jiabin9c07faf2023-04-26 22:00:44 +00001385 requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
1386 portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001387 }
1388 ALOGW("%s: unsupported audio port config: %s",
1389 __func__, requestedPortConfig.toString().c_str());
1390 return BAD_VALUE;
1391}
1392
1393DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
1394 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
1395 return std::find_if(mPatches.begin(), mPatches.end(),
1396 [&](const auto& pair) {
1397 const auto& p = pair.second;
1398 std::set<int32_t> patchSrcs(
1399 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
1400 std::set<int32_t> patchSinks(
1401 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
1402 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
1403}
1404
1405DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001406 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1407 return mPorts.find(mDefaultInputPortId);
1408 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1409 return mPorts.find(mDefaultOutputPortId);
1410 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001411 return std::find_if(mPorts.begin(), mPorts.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001412 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001413}
1414
1415DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001416 const AudioConfig& config, const AudioIoFlags& flags,
1417 const std::set<int32_t>& destinationPortIds) {
Mikhail Naganove93a0862023-03-15 17:06:59 -07001418 auto belongsToProfile = [&config](const AudioProfile& prof) {
1419 return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
1420 (config.base.channelMask.getTag() == AudioChannelLayout::none ||
1421 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
1422 config.base.channelMask) != prof.channelMasks.end()) &&
1423 (config.base.sampleRate == 0 ||
1424 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
1425 config.base.sampleRate) != prof.sampleRates.end());
1426 };
jiabin9c07faf2023-04-26 22:00:44 +00001427 static const std::vector<AudioOutputFlags> kOptionalOutputFlags{AudioOutputFlags::BIT_PERFECT};
1428 int optionalFlags = 0;
1429 auto flagMatches = [&flags, &optionalFlags](const AudioIoFlags& portFlags) {
1430 // Ports should be able to match if the optional flags are not requested.
1431 return portFlags == flags ||
1432 (portFlags.getTag() == AudioIoFlags::Tag::output &&
1433 AudioIoFlags::make<AudioIoFlags::Tag::output>(
1434 portFlags.get<AudioIoFlags::Tag::output>() &
1435 ~optionalFlags) == flags);
1436 };
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001437 auto matcher = [&](const auto& pair) {
1438 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001439 return p.ext.getTag() == AudioPortExt::Tag::mix &&
jiabin9c07faf2023-04-26 22:00:44 +00001440 flagMatches(p.flags) &&
Mikhail Naganov289468a2023-03-29 10:06:15 -07001441 (destinationPortIds.empty() ||
1442 std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
1443 [&](const int32_t destId) { return mRoutingMatrix.count(
1444 std::make_pair(p.id, destId)) != 0; })) &&
Mikhail Naganove93a0862023-03-15 17:06:59 -07001445 (p.profiles.empty() ||
1446 std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
1447 p.profiles.end()); };
jiabin9c07faf2023-04-26 22:00:44 +00001448 auto result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1449 if (result == mPorts.end() && flags.getTag() == AudioIoFlags::Tag::output) {
1450 auto optionalOutputFlagsIt = kOptionalOutputFlags.begin();
1451 while (result == mPorts.end() && optionalOutputFlagsIt != kOptionalOutputFlags.end()) {
1452 if (isBitPositionFlagSet(
1453 flags.get<AudioIoFlags::Tag::output>(), *optionalOutputFlagsIt)) {
1454 // If the flag is set by the request, it must be matched.
1455 ++optionalOutputFlagsIt;
1456 continue;
1457 }
1458 optionalFlags |= makeBitPositionFlagMask(*optionalOutputFlagsIt++);
1459 result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1460 ALOGI("%s: port for config %s, flags %s was not found in the module %s, "
1461 "retried with excluding optional flags %#x", __func__, config.toString().c_str(),
1462 flags.toString().c_str(), mInstance.c_str(), optionalFlags);
1463 }
1464 }
1465 return result;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001466}
1467
1468DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001469 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001470 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001471}
1472
1473DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001474 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001475 using Tag = AudioPortExt::Tag;
1476 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
1477 [&](const auto& pair) {
1478 const auto& p = pair.second;
1479 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
1480 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
1481 !p.format.has_value() || !p.flags.has_value(),
1482 "%s: stored mix port config is not fully specified: %s",
1483 __func__, p.toString().c_str());
1484 return p.ext.getTag() == Tag::mix &&
1485 isConfigEqualToPortConfig(config, p) &&
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001486 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001487 p.ext.template get<Tag::mix>().handle == ioHandle; });
1488}
Mikhail Naganove93a0862023-03-15 17:06:59 -07001489
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001490void DeviceHalAidl::resetPatch(int32_t patchId) {
1491 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1492 mPatches.erase(it);
1493 TIME_CHECK();
1494 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1495 ALOGE("%s: error while resetting patch %d: %s",
1496 __func__, patchId, status.getDescription().c_str());
1497 }
1498 return;
1499 }
1500 ALOGE("%s: patch id %d not found", __func__, patchId);
1501}
1502
1503void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1504 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1505 mPortConfigs.erase(it);
1506 TIME_CHECK();
1507 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1508 !status.isOk()) {
1509 ALOGE("%s: error while resetting port config %d: %s",
1510 __func__, portConfigId, status.getDescription().c_str());
1511 }
1512 return;
1513 }
1514 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1515}
1516
Mikhail Naganove93a0862023-03-15 17:06:59 -07001517void DeviceHalAidl::resetUnusedPatches() {
1518 // Since patches can be created independently of streams via 'createAudioPatch',
1519 // here we only clean up patches for released streams.
1520 for (auto it = mStreams.begin(); it != mStreams.end(); ) {
1521 if (auto streamSp = it->first.promote(); streamSp) {
1522 ++it;
1523 } else {
1524 resetPatch(it->second);
1525 it = mStreams.erase(it);
1526 }
1527 }
1528}
1529
1530void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
1531 resetUnusedPatches();
1532 resetUnusedPortConfigs();
1533}
1534
1535void DeviceHalAidl::resetUnusedPortConfigs() {
1536 // The assumption is that port configs are used to create patches
1537 // (or to open streams, but that involves creation of patches, too). Thus,
1538 // orphaned port configs can and should be reset.
1539 std::set<int32_t> portConfigIds;
1540 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
1541 std::inserter(portConfigIds, portConfigIds.end()),
1542 [](const auto& pcPair) { return pcPair.first; });
1543 for (const auto& p : mPatches) {
1544 for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
1545 for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
1546 }
jiabin9c07faf2023-04-26 22:00:44 +00001547 for (int32_t id : mInitialPortConfigIds) {
1548 portConfigIds.erase(id);
1549 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001550 for (int32_t id : portConfigIds) resetPortConfig(id);
1551}
1552
Mikhail Naganov289468a2023-03-29 10:06:15 -07001553status_t DeviceHalAidl::updateRoutes() {
1554 TIME_CHECK();
Mikhail Naganov289468a2023-03-29 10:06:15 -07001555 RETURN_STATUS_IF_ERROR(
Mikhail Naganovf83b9742023-04-24 13:06:04 -07001556 statusTFromBinderStatus(mModule->getAudioRoutes(&mRoutes)));
1557 ALOGW_IF(mRoutes.empty(), "%s: module %s returned an empty list of audio routes",
Mikhail Naganov289468a2023-03-29 10:06:15 -07001558 __func__, mInstance.c_str());
1559 mRoutingMatrix.clear();
Mikhail Naganovf83b9742023-04-24 13:06:04 -07001560 for (const auto& r : mRoutes) {
Mikhail Naganov289468a2023-03-29 10:06:15 -07001561 for (auto portId : r.sourcePortIds) {
1562 mRoutingMatrix.emplace(r.sinkPortId, portId);
1563 mRoutingMatrix.emplace(portId, r.sinkPortId);
1564 }
1565 }
1566 return OK;
1567}
1568
Mikhail Naganovdfd594e2023-02-08 16:59:41 -08001569void DeviceHalAidl::clearCallbacks(void* cookie) {
1570 std::lock_guard l(mLock);
1571 mCallbacks.erase(cookie);
1572}
1573
1574sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1575 return getCallbackImpl(cookie, &Callbacks::out);
1576}
1577
1578void DeviceHalAidl::setStreamOutCallback(
1579 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1580 setCallbackImpl(cookie, &Callbacks::out, cb);
1581}
1582
1583sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1584 void* cookie) {
1585 return getCallbackImpl(cookie, &Callbacks::event);
1586}
1587
1588void DeviceHalAidl::setStreamOutEventCallback(
1589 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1590 setCallbackImpl(cookie, &Callbacks::event, cb);
1591}
1592
1593sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1594 void* cookie) {
1595 return getCallbackImpl(cookie, &Callbacks::latency);
1596}
1597
1598void DeviceHalAidl::setStreamOutLatencyModeCallback(
1599 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1600 setCallbackImpl(cookie, &Callbacks::latency, cb);
1601}
1602
1603template<class C>
1604sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1605 std::lock_guard l(mLock);
1606 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1607 return ((it->second).*field).promote();
1608 }
1609 return nullptr;
1610}
1611template<class C>
1612void DeviceHalAidl::setCallbackImpl(
1613 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1614 std::lock_guard l(mLock);
1615 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1616 (it->second).*field = cb;
1617 }
1618}
1619
Mikhail Naganov31d46652023-01-10 18:29:25 +00001620} // namespace android