blob: 836dcf8c2f960f96058637c33198f9723a468335 [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) {
138 auto convertAudioPortFromMap = [](const Ports::value_type& pair) {
139 return ndk2cpp_AudioPort(pair.second);
140 };
141 return ::aidl::android::convertRange(mPorts.begin(), mPorts.end(), ports->begin(),
142 convertAudioPortFromMap);
143}
144
145status_t DeviceHalAidl::getAudioRoutes(std::vector<media::AudioRoute> *routes) {
146 *routes = VALUE_OR_RETURN_STATUS(
147 ::aidl::android::convertContainer<std::vector<media::AudioRoute>>(
148 mRoutes, ndk2cpp_AudioRoute));
149 return OK;
150}
151
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700152status_t DeviceHalAidl::getSupportedModes(std::vector<media::audio::common::AudioMode> *modes) {
153 TIME_CHECK();
154 if (modes == nullptr) {
155 return BAD_VALUE;
156 }
157 if (mModule == nullptr) return NO_INIT;
158 if (mTelephony == nullptr) return INVALID_OPERATION;
159 std::vector<AudioMode> aidlModes;
160 RETURN_STATUS_IF_ERROR(
161 statusTFromBinderStatus(mTelephony->getSupportedAudioModes(&aidlModes)));
162 *modes = VALUE_OR_RETURN_STATUS(
163 ::aidl::android::convertContainer<std::vector<media::audio::common::AudioMode>>(
164 aidlModes, ndk2cpp_AudioMode));
165 return OK;
166}
167
Mikhail Naganov31d46652023-01-10 18:29:25 +0000168status_t DeviceHalAidl::getSupportedDevices(uint32_t*) {
169 // Obsolete.
170 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +0000171}
172
173status_t DeviceHalAidl::initCheck() {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800174 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000175 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800176 std::vector<AudioPort> ports;
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700177 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800178 ALOGW_IF(ports.empty(), "%s: module %s returned an empty list of audio ports",
179 __func__, mInstance.c_str());
180 std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()),
181 [](const auto& p) { return std::make_pair(p.id, p); });
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800182 mDefaultInputPortId = mDefaultOutputPortId = -1;
183 const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
184 for (const auto& pair : mPorts) {
185 const auto& p = pair.second;
186 if (p.ext.getTag() == AudioPortExt::Tag::device &&
187 (p.ext.get<AudioPortExt::Tag::device>().flags & defaultDeviceFlag) != 0) {
188 if (p.flags.getTag() == AudioIoFlags::Tag::input) {
189 mDefaultInputPortId = p.id;
190 } else if (p.flags.getTag() == AudioIoFlags::Tag::output) {
191 mDefaultOutputPortId = p.id;
192 }
193 }
194 }
195 ALOGI("%s: module %s default port ids: input %d, output %d",
196 __func__, mInstance.c_str(), mDefaultInputPortId, mDefaultOutputPortId);
Mikhail Naganov289468a2023-03-29 10:06:15 -0700197 RETURN_STATUS_IF_ERROR(updateRoutes());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800198 std::vector<AudioPortConfig> portConfigs;
199 RETURN_STATUS_IF_ERROR(
200 statusTFromBinderStatus(mModule->getAudioPortConfigs(&portConfigs))); // OK if empty
201 std::transform(portConfigs.begin(), portConfigs.end(),
202 std::inserter(mPortConfigs, mPortConfigs.end()),
203 [](const auto& p) { return std::make_pair(p.id, p); });
jiabin9c07faf2023-04-26 22:00:44 +0000204 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
205 std::inserter(mInitialPortConfigIds, mInitialPortConfigIds.end()),
206 [](const auto& pcPair) { return pcPair.first; });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800207 std::vector<AudioPatch> patches;
208 RETURN_STATUS_IF_ERROR(
209 statusTFromBinderStatus(mModule->getAudioPatches(&patches))); // OK if empty
210 std::transform(patches.begin(), patches.end(),
211 std::inserter(mPatches, mPatches.end()),
212 [](const auto& p) { return std::make_pair(p.id, p); });
Shunkai Yao51202502022-12-12 06:11:46 +0000213 return OK;
214}
215
216status_t DeviceHalAidl::setVoiceVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000217 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000218 if (!mModule) return NO_INIT;
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700219 if (mTelephony == nullptr) return INVALID_OPERATION;
220 ITelephony::TelecomConfig inConfig{ .voiceVolume = Float{volume} }, outConfig;
221 RETURN_STATUS_IF_ERROR(
222 statusTFromBinderStatus(mTelephony->setTelecomConfig(inConfig, &outConfig)));
223 ALOGW_IF(outConfig.voiceVolume.has_value() && volume != outConfig.voiceVolume.value().value,
224 "%s: the resulting voice volume %f is not the same as requested %f",
225 __func__, outConfig.voiceVolume.value().value, volume);
226 return OK;
Shunkai Yao51202502022-12-12 06:11:46 +0000227}
228
229status_t DeviceHalAidl::setMasterVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000230 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000231 if (!mModule) return NO_INIT;
232 return statusTFromBinderStatus(mModule->setMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000233}
234
235status_t DeviceHalAidl::getMasterVolume(float *volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000236 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000237 if (!mModule) return NO_INIT;
238 return statusTFromBinderStatus(mModule->getMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000239}
240
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000241status_t DeviceHalAidl::setMode(audio_mode_t mode) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000242 TIME_CHECK();
243 if (!mModule) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000244 AudioMode audioMode = VALUE_OR_FATAL(::aidl::android::legacy2aidl_audio_mode_t_AudioMode(mode));
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700245 if (mTelephony != nullptr) {
246 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mTelephony->switchAudioMode(audioMode)));
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000247 }
248 return statusTFromBinderStatus(mModule->updateAudioMode(audioMode));
Shunkai Yao51202502022-12-12 06:11:46 +0000249}
250
251status_t DeviceHalAidl::setMicMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000252 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000253 if (!mModule) return NO_INIT;
254 return statusTFromBinderStatus(mModule->setMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000255}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000256
Shunkai Yao51202502022-12-12 06:11:46 +0000257status_t DeviceHalAidl::getMicMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000258 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000259 if (!mModule) return NO_INIT;
260 return statusTFromBinderStatus(mModule->getMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000261}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000262
Shunkai Yao51202502022-12-12 06:11:46 +0000263status_t DeviceHalAidl::setMasterMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000264 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000265 if (!mModule) return NO_INIT;
266 return statusTFromBinderStatus(mModule->setMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000267}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000268
Shunkai Yao51202502022-12-12 06:11:46 +0000269status_t DeviceHalAidl::getMasterMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000270 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000271 if (!mModule) return NO_INIT;
272 return statusTFromBinderStatus(mModule->getMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000273}
274
Mikhail Naganovccc82112023-04-27 18:14:15 -0700275status_t DeviceHalAidl::setParameters(const String8& kvPairs) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000276 if (!mModule) return NO_INIT;
Mikhail Naganovccc82112023-04-27 18:14:15 -0700277 AudioParameter parameters(kvPairs);
278 ALOGD("%s: parameters: \"%s\"", __func__, parameters.toString().c_str());
279
280 if (status_t status = filterAndUpdateBtA2dpParameters(parameters); status != OK) {
281 ALOGW("%s: filtering or updating BT A2DP parameters failed: %d", __func__, status);
282 }
283 if (status_t status = filterAndUpdateBtHfpParameters(parameters); status != OK) {
284 ALOGW("%s: filtering or updating BT HFP parameters failed: %d", __func__, status);
285 }
286 if (status_t status = filterAndUpdateBtLeParameters(parameters); status != OK) {
287 ALOGW("%s: filtering or updating BT LE parameters failed: %d", __func__, status);
288 }
289 if (status_t status = filterAndUpdateBtScoParameters(parameters); status != OK) {
290 ALOGW("%s: filtering or updating BT SCO parameters failed: %d", __func__, status);
291 }
292
293 ALOGW_IF(parameters.size() != 0, "%s: unknown parameters, ignored: \"%s\"",
294 __func__, parameters.toString().c_str());
Shunkai Yao51202502022-12-12 06:11:46 +0000295 return OK;
296}
297
Mikhail Naganov31d46652023-01-10 18:29:25 +0000298status_t DeviceHalAidl::getParameters(const String8& keys __unused, String8 *values) {
299 TIME_CHECK();
Mikhail Naganovccc82112023-04-27 18:14:15 -0700300 // FIXME(b/278976019): Support keyReconfigA2dpSupported via vendor plugin
Mikhail Naganov31d46652023-01-10 18:29:25 +0000301 values->clear();
302 if (!mModule) return NO_INIT;
303 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000304 return OK;
305}
306
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800307namespace {
308
309class Cleanup {
310 public:
311 typedef void (DeviceHalAidl::*Cleaner)(int32_t);
312
313 Cleanup(DeviceHalAidl* device, Cleaner cleaner, int32_t id) :
314 mDevice(device), mCleaner(cleaner), mId(id) {}
315 ~Cleanup() { clean(); }
316 void clean() {
317 if (mDevice != nullptr) (mDevice->*mCleaner)(mId);
318 disarm();
319 }
320 void disarm() { mDevice = nullptr; }
321
322 private:
323 DeviceHalAidl* mDevice;
324 const Cleaner mCleaner;
325 const int32_t mId;
326};
327
328} // namespace
329
330// Since the order of container elements destruction is unspecified,
331// ensure that cleanups are performed from the most recent one and upwards.
332// This is the same as if there were individual Cleanup instances on the stack,
333// however the bonus is that we can disarm all of them with just one statement.
334class DeviceHalAidl::Cleanups : public std::forward_list<Cleanup> {
335 public:
336 ~Cleanups() { for (auto& c : *this) c.clean(); }
337 void disarmAll() { for (auto& c : *this) c.disarm(); }
338};
339
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800340status_t DeviceHalAidl::getInputBufferSize(const struct audio_config* config, size_t* size) {
341 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
342 if (size == nullptr) return BAD_VALUE;
343 TIME_CHECK();
344 if (!mModule) return NO_INIT;
345 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
346 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
347 AudioDevice aidlDevice;
348 aidlDevice.type.type = AudioDeviceType::IN_DEFAULT;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800349 AudioSource aidlSource = AudioSource::DEFAULT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800350 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
351 AudioPortConfig mixPortConfig;
352 Cleanups cleanups;
353 audio_config writableConfig = *config;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700354 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800355 RETURN_STATUS_IF_ERROR(prepareToOpenStream(0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700356 &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800357 *size = aidlConfig.frameCount *
358 getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
359 // Do not disarm cleanups to release temporary port configs.
360 return OK;
361}
362
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800363status_t DeviceHalAidl::prepareToOpenStream(
364 int32_t aidlHandle, const AudioDevice& aidlDevice, const AudioIoFlags& aidlFlags,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800365 AudioSource aidlSource, struct audio_config* config,
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800366 Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700367 AudioPatch* aidlPatch) {
368 ALOGD("%p %s::%s: handle %d, device %s, flags %s, source %s, config %s, mix port config %s",
369 this, getClassName().c_str(), __func__, aidlHandle, aidlDevice.toString().c_str(),
370 aidlFlags.toString().c_str(), toString(aidlSource).c_str(),
371 aidlConfig->toString().c_str(), mixPortConfig->toString().c_str());
jiabin9c07faf2023-04-26 22:00:44 +0000372 resetUnusedPatchesAndPortConfigs();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800373 const bool isInput = aidlFlags.getTag() == AudioIoFlags::Tag::input;
374 // Find / create AudioPortConfigs for the device port and the mix port,
375 // then find / create a patch between them, and open a stream on the mix port.
376 AudioPortConfig devicePortConfig;
377 bool created = false;
jiabin9c07faf2023-04-26 22:00:44 +0000378 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, aidlConfig,
379 &devicePortConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800380 if (created) {
381 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
382 }
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800383 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*aidlConfig, aidlFlags, aidlHandle, aidlSource,
Mikhail Naganov289468a2023-03-29 10:06:15 -0700384 std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800385 if (created) {
386 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
387 }
388 setConfigFromPortConfig(aidlConfig, *mixPortConfig);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800389 if (isInput) {
390 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700391 {devicePortConfig.id}, {mixPortConfig->id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800392 } else {
393 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700394 {mixPortConfig->id}, {devicePortConfig.id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800395 }
396 if (created) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700397 cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, aidlPatch->id);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800398 }
399 if (aidlConfig->frameCount <= 0) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700400 aidlConfig->frameCount = aidlPatch->minimumStreamBufferSizeFrames;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800401 }
402 *config = VALUE_OR_RETURN_STATUS(
403 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(*aidlConfig, isInput));
404 return OK;
405}
406
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800407namespace {
408
409class StreamCallbackBase {
410 protected:
411 explicit StreamCallbackBase(const sp<CallbackBroker>& broker) : mBroker(broker) {}
412 public:
413 void* getCookie() const { return mCookie; }
414 void setCookie(void* cookie) { mCookie = cookie; }
415 sp<CallbackBroker> getBroker() const {
416 if (void* cookie = mCookie; cookie != nullptr) return mBroker.promote();
417 return nullptr;
418 }
419 private:
420 const wp<CallbackBroker> mBroker;
421 std::atomic<void*> mCookie;
422};
423
424template<class C>
425class StreamCallbackBaseHelper {
426 protected:
427 explicit StreamCallbackBaseHelper(const StreamCallbackBase& base) : mBase(base) {}
428 sp<C> getCb(const sp<CallbackBroker>& broker, void* cookie);
429 using CbRef = const sp<C>&;
430 ndk::ScopedAStatus runCb(const std::function<void(CbRef cb)>& f) {
431 if (auto cb = getCb(mBase.getBroker(), mBase.getCookie()); cb != nullptr) f(cb);
432 return ndk::ScopedAStatus::ok();
433 }
434 private:
435 const StreamCallbackBase& mBase;
436};
437
438template<>
439sp<StreamOutHalInterfaceCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>::getCb(
440 const sp<CallbackBroker>& broker, void* cookie) {
441 if (broker != nullptr) return broker->getStreamOutCallback(cookie);
442 return nullptr;
443}
444
445template<>
446sp<StreamOutHalInterfaceEventCallback>
447StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::getCb(
448 const sp<CallbackBroker>& broker, void* cookie) {
449 if (broker != nullptr) return broker->getStreamOutEventCallback(cookie);
450 return nullptr;
451}
452
453template<>
454sp<StreamOutHalInterfaceLatencyModeCallback>
455StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::getCb(
456 const sp<CallbackBroker>& broker, void* cookie) {
457 if (broker != nullptr) return broker->getStreamOutLatencyModeCallback(cookie);
458 return nullptr;
459}
460
461/*
462Note on the callback ownership.
463
464In the Binder ownership model, the server implementation is kept alive
465as long as there is any client (proxy object) alive. This is done by
466incrementing the refcount of the server-side object by the Binder framework.
467When it detects that the last client is gone, it decrements the refcount back.
468
469Thus, it is not needed to keep any references to StreamCallback on our
470side (after we have sent an instance to the client), because we are
471the server-side. The callback object will be kept alive as long as the HAL server
472holds a strong ref to IStreamCallback proxy.
473*/
474
475class OutputStreamCallbackAidl : public StreamCallbackBase,
476 public StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>,
477 public ::aidl::android::hardware::audio::core::BnStreamCallback {
478 public:
479 explicit OutputStreamCallbackAidl(const sp<CallbackBroker>& broker)
480 : StreamCallbackBase(broker),
481 StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>(
482 *static_cast<StreamCallbackBase*>(this)) {}
483 ndk::ScopedAStatus onTransferReady() override {
484 return runCb([](CbRef cb) { cb->onWriteReady(); });
485 }
486 ndk::ScopedAStatus onError() override {
487 return runCb([](CbRef cb) { cb->onError(); });
488 }
489 ndk::ScopedAStatus onDrainReady() override {
490 return runCb([](CbRef cb) { cb->onDrainReady(); });
491 }
492};
493
494class OutputStreamEventCallbackAidl :
495 public StreamCallbackBase,
496 public StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>,
497 public StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>,
498 public ::aidl::android::hardware::audio::core::BnStreamOutEventCallback {
499 public:
500 explicit OutputStreamEventCallbackAidl(const sp<CallbackBroker>& broker)
501 : StreamCallbackBase(broker),
502 StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>(
503 *static_cast<StreamCallbackBase*>(this)),
504 StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>(
505 *static_cast<StreamCallbackBase*>(this)) {}
506 ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& in_audioMetadata) override {
507 std::basic_string<uint8_t> halMetadata(in_audioMetadata.begin(), in_audioMetadata.end());
508 return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb(
509 [&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); });
510 }
511 ndk::ScopedAStatus onRecommendedLatencyModeChanged(
512 const std::vector<AudioLatencyMode>& in_modes) override {
513 auto halModes = VALUE_OR_FATAL(
514 ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
515 in_modes,
516 ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
517 return StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::runCb(
518 [&halModes](auto cb) { cb->onRecommendedLatencyModeChanged(halModes); });
519 }
520};
521
522} // namespace
523
Mikhail Naganov31d46652023-01-10 18:29:25 +0000524status_t DeviceHalAidl::openOutputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800525 audio_io_handle_t handle, audio_devices_t devices,
526 audio_output_flags_t flags, struct audio_config* config,
527 const char* address,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000528 sp<StreamOutHalInterface>* outStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800529 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000530 if (!outStream || !config) {
531 return BAD_VALUE;
532 }
533 TIME_CHECK();
534 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800535 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
536 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
537 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
538 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, false /*isInput*/));
539 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
540 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
541 int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
542 ::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
543 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
544 AudioPortConfig mixPortConfig;
545 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700546 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800547 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
548 AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700549 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800550 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
551 args.portConfigId = mixPortConfig.id;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800552 const bool isOffload = isBitPositionFlagSet(
553 aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD);
554 std::shared_ptr<OutputStreamCallbackAidl> streamCb;
555 if (isOffload) {
556 streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
557 }
558 auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
559 if (isOffload) {
560 args.offloadInfo = aidlConfig.offloadInfo;
561 args.callback = streamCb;
562 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800563 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800564 args.eventCallback = eventCb;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800565 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
566 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800567 StreamContextAidl context(ret.desc, isOffload);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800568 if (!context.isValid()) {
569 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
570 __func__, ret.desc.toString().c_str());
571 return NO_INIT;
572 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700573 *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800574 std::move(ret.stream), this /*callbackBroker*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700575 mStreams.insert(std::pair(*outStream, aidlPatch.id));
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800576 void* cbCookie = (*outStream).get();
577 {
578 std::lock_guard l(mLock);
579 mCallbacks.emplace(cbCookie, Callbacks{});
580 }
581 if (streamCb) streamCb->setCookie(cbCookie);
582 eventCb->setCookie(cbCookie);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800583 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000584 return OK;
585}
586
Mikhail Naganov31d46652023-01-10 18:29:25 +0000587status_t DeviceHalAidl::openInputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800588 audio_io_handle_t handle, audio_devices_t devices,
589 struct audio_config* config, audio_input_flags_t flags,
590 const char* address, audio_source_t source,
591 audio_devices_t outputDevice, const char* outputDeviceAddress,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000592 sp<StreamInHalInterface>* inStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800593 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000594 if (!inStream || !config) {
595 return BAD_VALUE;
596 }
597 TIME_CHECK();
598 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800599 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
600 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
601 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
602 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
603 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
604 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
605 int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
606 ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
607 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
608 AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
609 ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
610 AudioPortConfig mixPortConfig;
611 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700612 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800613 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700614 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800615 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
616 args.portConfigId = mixPortConfig.id;
617 RecordTrackMetadata aidlTrackMetadata{
618 .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
619 if (outputDevice != AUDIO_DEVICE_NONE) {
620 aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
621 ::aidl::android::legacy2aidl_audio_device_AudioDevice(
622 outputDevice, outputDeviceAddress));
623 }
624 args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
625 args.bufferSizeFrames = aidlConfig.frameCount;
626 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
627 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800628 StreamContextAidl context(ret.desc, false /*isAsynchronous*/);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800629 if (!context.isValid()) {
630 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
631 __func__, ret.desc.toString().c_str());
632 return NO_INIT;
633 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700634 *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800635 std::move(ret.stream), this /*micInfoProvider*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700636 mStreams.insert(std::pair(*inStream, aidlPatch.id));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800637 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000638 return OK;
639}
640
641status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
642 *supportsPatches = true;
643 return OK;
644}
645
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800646status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
647 const struct audio_port_config* sources,
648 unsigned int num_sinks,
649 const struct audio_port_config* sinks,
650 audio_patch_handle_t* patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800651 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000652 TIME_CHECK();
653 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800654 if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
655 sources == nullptr || sinks == nullptr || patch == nullptr) {
656 return BAD_VALUE;
657 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800658 // When the patch handle (*patch) is AUDIO_PATCH_HANDLE_NONE, it means
659 // the framework wants to create a new patch. The handle has to be generated
660 // by the HAL. Since handles generated this way can only be unique within
661 // a HAL module, the framework generates a globally unique handle, and maps
662 // it on the <HAL module, patch handle> pair.
663 // When the patch handle is set, it meant the framework intends to update
664 // an existing patch.
665 //
666 // This behavior corresponds to HAL module behavior, with the only difference
667 // that the HAL module uses `int32_t` for patch IDs. The following assert ensures
668 // that both the framework and the HAL use the same value for "no ID":
669 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
670 int32_t halPatchId = static_cast<int32_t>(*patch);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800671
672 // Upon conversion, mix port configs contain audio configuration, while
673 // device port configs contain device address. This data is used to find
674 // or create HAL configs.
675 std::vector<AudioPortConfig> aidlSources, aidlSinks;
676 for (unsigned int i = 0; i < num_sources; ++i) {
677 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
678 sources[i].role, sources[i].type)) ==
679 ::aidl::android::AudioPortDirection::INPUT;
680 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
681 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
682 sources[i], isInput, 0)));
683 }
684 for (unsigned int i = 0; i < num_sinks; ++i) {
685 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
686 sinks[i].role, sinks[i].type)) ==
687 ::aidl::android::AudioPortDirection::INPUT;
688 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
689 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
690 sinks[i], isInput, 0)));
691 }
692 Cleanups cleanups;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800693 auto existingPatchIt = halPatchId != 0 ? mPatches.find(halPatchId): mPatches.end();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800694 AudioPatch aidlPatch;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800695 if (existingPatchIt != mPatches.end()) {
696 aidlPatch = existingPatchIt->second;
697 aidlPatch.sourcePortConfigIds.clear();
698 aidlPatch.sinkPortConfigIds.clear();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800699 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800700 ALOGD("%s: sources: %s, sinks: %s",
701 __func__, ::android::internal::ToString(aidlSources).c_str(),
702 ::android::internal::ToString(aidlSinks).c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800703 auto fillPortConfigs = [&](
Mikhail Naganov289468a2023-03-29 10:06:15 -0700704 const std::vector<AudioPortConfig>& configs,
705 const std::set<int32_t>& destinationPortIds,
706 std::vector<int32_t>* ids, std::set<int32_t>* portIds) -> status_t {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800707 for (const auto& s : configs) {
708 AudioPortConfig portConfig;
709 bool created = false;
Mikhail Naganov289468a2023-03-29 10:06:15 -0700710 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
711 s, destinationPortIds, &portConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800712 if (created) {
713 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, portConfig.id);
714 }
715 ids->push_back(portConfig.id);
Mikhail Naganov289468a2023-03-29 10:06:15 -0700716 if (portIds != nullptr) {
717 portIds->insert(portConfig.portId);
718 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800719 }
720 return OK;
721 };
Mikhail Naganov289468a2023-03-29 10:06:15 -0700722 // When looking up port configs, the destinationPortId is only used for mix ports.
723 // Thus, we process device port configs first, and look up the destination port ID from them.
724 bool sourceIsDevice = std::any_of(aidlSources.begin(), aidlSources.end(),
725 [](const auto& config) { return config.ext.getTag() == AudioPortExt::device; });
726 const std::vector<AudioPortConfig>& devicePortConfigs =
727 sourceIsDevice ? aidlSources : aidlSinks;
728 std::vector<int32_t>* devicePortConfigIds =
729 sourceIsDevice ? &aidlPatch.sourcePortConfigIds : &aidlPatch.sinkPortConfigIds;
730 const std::vector<AudioPortConfig>& mixPortConfigs =
731 sourceIsDevice ? aidlSinks : aidlSources;
732 std::vector<int32_t>* mixPortConfigIds =
733 sourceIsDevice ? &aidlPatch.sinkPortConfigIds : &aidlPatch.sourcePortConfigIds;
734 std::set<int32_t> devicePortIds;
735 RETURN_STATUS_IF_ERROR(fillPortConfigs(
736 devicePortConfigs, std::set<int32_t>(), devicePortConfigIds, &devicePortIds));
737 RETURN_STATUS_IF_ERROR(fillPortConfigs(
738 mixPortConfigs, devicePortIds, mixPortConfigIds, nullptr));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800739 if (existingPatchIt != mPatches.end()) {
740 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
741 mModule->setAudioPatch(aidlPatch, &aidlPatch)));
742 existingPatchIt->second = aidlPatch;
743 } else {
744 bool created = false;
745 RETURN_STATUS_IF_ERROR(findOrCreatePatch(aidlPatch, &aidlPatch, &created));
746 // Since no cleanup of the patch is needed, 'created' is ignored.
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800747 halPatchId = aidlPatch.id;
748 *patch = static_cast<audio_patch_handle_t>(halPatchId);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800749 }
750 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000751 return OK;
752}
753
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800754status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800755 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000756 TIME_CHECK();
757 if (!mModule) return NO_INIT;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800758 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
759 if (patch == AUDIO_PATCH_HANDLE_NONE) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800760 return BAD_VALUE;
761 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800762 int32_t halPatchId = static_cast<int32_t>(patch);
763 auto patchIt = mPatches.find(halPatchId);
764 if (patchIt == mPatches.end()) {
765 ALOGE("%s: patch with id %d not found", __func__, halPatchId);
766 return BAD_VALUE;
767 }
768 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->resetAudioPatch(halPatchId)));
769 mPatches.erase(patchIt);
Shunkai Yao51202502022-12-12 06:11:46 +0000770 return OK;
771}
772
Mikhail Naganove93a0862023-03-15 17:06:59 -0700773status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
774 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000775 TIME_CHECK();
776 if (!mModule) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700777 if (port == nullptr) {
778 return BAD_VALUE;
779 }
780 audio_port_v7 portV7;
781 audio_populate_audio_port_v7(port, &portV7);
782 RETURN_STATUS_IF_ERROR(getAudioPort(&portV7));
783 return audio_populate_audio_port(&portV7, port) ? OK : BAD_VALUE;
784}
785
786status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
787 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
788 TIME_CHECK();
789 if (!mModule) return NO_INIT;
790 if (port == nullptr) {
791 return BAD_VALUE;
792 }
793 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
794 ::aidl::android::AudioPortDirection::INPUT;
795 auto aidlPort = VALUE_OR_RETURN_STATUS(
796 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
797 if (aidlPort.ext.getTag() != AudioPortExt::device) {
798 ALOGE("%s: provided port is not a device port (module %s): %s",
799 __func__, mInstance.c_str(), aidlPort.toString().c_str());
800 return BAD_VALUE;
801 }
802 const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
803 // It seems that we don't have to call HAL since all valid ports have been added either
804 // during initialization, or while handling connection of an external device.
805 auto portsIt = findPort(matchDevice);
806 if (portsIt == mPorts.end()) {
807 ALOGE("%s: device port for device %s is not found in the module %s",
808 __func__, matchDevice.toString().c_str(), mInstance.c_str());
809 return BAD_VALUE;
810 }
811 const int32_t fwkId = aidlPort.id;
812 aidlPort = portsIt->second;
813 aidlPort.id = fwkId;
814 *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
815 aidlPort, isInput));
816 return OK;
817}
818
819status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
820 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
821 TIME_CHECK();
822 if (!mModule) return NO_INIT;
823 if (config == nullptr) {
824 return BAD_VALUE;
825 }
826 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
827 config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
828 AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
829 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
830 *config, isInput, 0 /*portId*/));
831 AudioPortConfig portConfig;
832 bool created = false;
Mikhail Naganov289468a2023-03-29 10:06:15 -0700833 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
834 requestedPortConfig, std::set<int32_t>(), &portConfig, &created));
Shunkai Yao51202502022-12-12 06:11:46 +0000835 return OK;
836}
837
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800838MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
839 if (mMicrophones.status == Microphones::Status::UNKNOWN) {
840 TIME_CHECK();
841 std::vector<MicrophoneInfo> aidlInfo;
842 status_t status = statusTFromBinderStatus(mModule->getMicrophones(&aidlInfo));
843 if (status == OK) {
844 mMicrophones.status = Microphones::Status::QUERIED;
845 mMicrophones.info = std::move(aidlInfo);
846 } else if (status == INVALID_OPERATION) {
847 mMicrophones.status = Microphones::Status::NOT_SUPPORTED;
848 } else {
849 ALOGE("%s: Unexpected status from 'IModule.getMicrophones': %d", __func__, status);
850 return {};
851 }
852 }
853 if (mMicrophones.status == Microphones::Status::QUERIED) {
854 return &mMicrophones.info;
855 }
856 return {}; // NOT_SUPPORTED
857}
858
Shunkai Yao51202502022-12-12 06:11:46 +0000859status_t DeviceHalAidl::getMicrophones(
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800860 std::vector<audio_microphone_characteristic_t>* microphones) {
861 if (!microphones) {
862 return BAD_VALUE;
863 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000864 TIME_CHECK();
865 if (!mModule) return NO_INIT;
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800866 auto staticInfo = getMicrophoneInfo();
867 if (!staticInfo) return INVALID_OPERATION;
868 std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
869 emptyDynamicInfo.reserve(staticInfo->size());
870 std::transform(staticInfo->begin(), staticInfo->end(), std::back_inserter(emptyDynamicInfo),
871 [](const auto& info) { return MicrophoneDynamicInfo{ .id = info.id }; });
872 *microphones = VALUE_OR_RETURN_STATUS(
873 ::aidl::android::convertContainers<std::vector<audio_microphone_characteristic_t>>(
874 *staticInfo, emptyDynamicInfo,
875 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t)
876 );
Shunkai Yao51202502022-12-12 06:11:46 +0000877 return OK;
878}
879
Mikhail Naganov31d46652023-01-10 18:29:25 +0000880status_t DeviceHalAidl::addDeviceEffect(audio_port_handle_t device __unused,
881 sp<EffectHalInterface> effect) {
Shunkai Yao51202502022-12-12 06:11:46 +0000882 if (!effect) {
883 return BAD_VALUE;
884 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000885 TIME_CHECK();
886 if (!mModule) return NO_INIT;
887 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000888 return OK;
889}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000890status_t DeviceHalAidl::removeDeviceEffect(audio_port_handle_t device __unused,
Shunkai Yao51202502022-12-12 06:11:46 +0000891 sp<EffectHalInterface> effect) {
892 if (!effect) {
893 return BAD_VALUE;
894 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000895 TIME_CHECK();
896 if (!mModule) return NO_INIT;
897 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000898 return OK;
899}
900
901status_t DeviceHalAidl::getMmapPolicyInfos(
David Li9cf5e622023-03-21 00:51:10 +0800902 media::audio::common::AudioMMapPolicyType policyType,
903 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000904 TIME_CHECK();
Mikhail Naganov25bc9a22023-04-21 18:48:16 -0700905 AudioMMapPolicyType mmapPolicyType = VALUE_OR_RETURN_STATUS(
906 cpp2ndk_AudioMMapPolicyType(policyType));
David Li9cf5e622023-03-21 00:51:10 +0800907
908 std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
909
910 if (status_t status = statusTFromBinderStatus(
911 mModule->getMmapPolicyInfos(mmapPolicyType, &mmapPolicyInfos)); status != OK) {
912 return status;
913 }
914
915 *policyInfos = VALUE_OR_RETURN_STATUS(
916 convertContainer<std::vector<media::audio::common::AudioMMapPolicyInfo>>(
917 mmapPolicyInfos, ndk2cpp_AudioMMapPolicyInfo));
Shunkai Yao51202502022-12-12 06:11:46 +0000918 return OK;
919}
920
921int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000922 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800923 int32_t mixerBurstCount = 0;
924 if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
925 return mixerBurstCount;
926 }
927 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000928}
929
930int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000931 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800932 int32_t hardwareBurstMinUsec = 0;
933 if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
934 return hardwareBurstMinUsec;
935 }
936 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000937}
938
939error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000940 TIME_CHECK();
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700941 if (!mModule) return NO_INIT;
942 int32_t aidlHwAvSync;
943 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
944 return VALUE_OR_RETURN_STATUS(
945 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +0000946}
947
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000948status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
949 TIME_CHECK();
950 if (!mModule) return NO_INIT;
951 return mModule->dump(fd, Args(args).args(), args.size());
David Li9cf5e622023-03-21 00:51:10 +0800952}
Shunkai Yao51202502022-12-12 06:11:46 +0000953
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700954int32_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000955 TIME_CHECK();
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700956 if (!mModule) return NO_INIT;
957 if (supports == nullptr) {
958 return BAD_VALUE;
959 }
960 return statusTFromBinderStatus(mModule->supportsVariableLatency(supports));
Shunkai Yao51202502022-12-12 06:11:46 +0000961}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000962
jiabin872de702023-04-27 22:04:31 +0000963
964status_t DeviceHalAidl::prepareToDisconnectExternalDevice(const struct audio_port_v7* port) {
965 // There is not AIDL API defined for `prepareToDisconnectExternalDevice`.
966 // Call `setConnectedState` instead.
967 // TODO(b/279824103): call prepareToDisconnectExternalDevice when it is added.
968 const status_t status = setConnectedState(port, false /*connected*/);
969 if (status == NO_ERROR) {
970 mDeviceDisconnectionNotified.insert(port->id);
971 }
972 return status;
973}
974
Mikhail Naganove93a0862023-03-15 17:06:59 -0700975status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
976 TIME_CHECK();
977 if (!mModule) return NO_INIT;
978 if (port == nullptr) {
979 return BAD_VALUE;
980 }
jiabin872de702023-04-27 22:04:31 +0000981 if (!connected && mDeviceDisconnectionNotified.erase(port->id) > 0) {
982 // For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
983 // and then call `setConnectedState`. However, there is no API for
984 // `prepareToDisconnectExternalDevice` yet. In that case, `setConnectedState` will be
985 // called when calling `prepareToDisconnectExternalDevice`. Do not call to the HAL if
986 // previous call is successful. Also remove the cache here to avoid a large cache after
987 // a long run.
988 return NO_ERROR;
989 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700990 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
991 ::aidl::android::AudioPortDirection::INPUT;
992 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
993 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
994 if (aidlPort.ext.getTag() != AudioPortExt::device) {
995 ALOGE("%s: provided port is not a device port (module %s): %s",
996 __func__, mInstance.c_str(), aidlPort.toString().c_str());
997 return BAD_VALUE;
998 }
999 if (connected) {
1000 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1001 // Reset the device address to find the "template" port.
1002 matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
1003 auto portsIt = findPort(matchDevice);
1004 if (portsIt == mPorts.end()) {
1005 ALOGW("%s: device port for device %s is not found in the module %s",
1006 __func__, matchDevice.toString().c_str(), mInstance.c_str());
1007 return BAD_VALUE;
1008 }
1009 // Use the ID of the "template" port, use all the information from the provided port.
1010 aidlPort.id = portsIt->first;
1011 AudioPort connectedPort;
1012 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
1013 aidlPort, &connectedPort)));
1014 const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
1015 LOG_ALWAYS_FATAL_IF(!inserted,
1016 "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
1017 __func__, mInstance.c_str(), connectedPort.toString().c_str(),
1018 it->second.toString().c_str());
1019 } else { // !connected
1020 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1021 auto portsIt = findPort(matchDevice);
1022 if (portsIt == mPorts.end()) {
1023 ALOGW("%s: device port for device %s is not found in the module %s",
1024 __func__, matchDevice.toString().c_str(), mInstance.c_str());
1025 return BAD_VALUE;
1026 }
1027 // Any streams opened on the external device must be closed by this time,
1028 // thus we can clean up patches and port configs that were created for them.
1029 resetUnusedPatchesAndPortConfigs();
1030 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
1031 portsIt->second.id)));
1032 mPorts.erase(portsIt);
1033 }
Mikhail Naganov289468a2023-03-29 10:06:15 -07001034 return updateRoutes();
Mikhail Naganove93a0862023-03-15 17:06:59 -07001035}
1036
1037status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
1038 TIME_CHECK();
1039 if (!mModule) return NO_INIT;
1040 ModuleDebug debug{ .simulateDeviceConnections = enabled };
1041 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
1042 // This is important to log as it affects HAL behavior.
1043 if (status == OK) {
1044 ALOGI("%s: set enabled: %d", __func__, enabled);
1045 } else {
1046 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
1047 }
1048 return status;
1049}
1050
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001051bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
1052 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1053 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1054}
1055
1056bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
1057 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1058 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1059 return p.portId == mDefaultInputPortId;
1060 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1061 return p.portId == mDefaultOutputPortId;
1062 }
1063 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1064}
1065
David Lia8675d42023-03-30 21:08:06 +08001066status_t DeviceHalAidl::createOrUpdatePortConfig(
1067 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool* created) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001068 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001069 AudioPortConfig appliedPortConfig;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001070 bool applied = false;
1071 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001072 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001073 if (!applied) {
1074 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001075 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001076 if (!applied) {
1077 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001078 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001079 return NO_INIT;
1080 }
1081 }
David Lia8675d42023-03-30 21:08:06 +08001082
1083 int32_t id = appliedPortConfig.id;
1084 if (requestedPortConfig.id != 0 && requestedPortConfig.id != id) {
1085 LOG_ALWAYS_FATAL("%s: requested port config id %d changed to %d", __func__,
1086 requestedPortConfig.id, id);
1087 }
1088
1089 auto [it, inserted] = mPortConfigs.insert_or_assign(std::move(id),
1090 std::move(appliedPortConfig));
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001091 *result = it;
David Lia8675d42023-03-30 21:08:06 +08001092 *created = inserted;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001093 return OK;
1094}
1095
Mikhail Naganovccc82112023-04-27 18:14:15 -07001096status_t DeviceHalAidl::filterAndUpdateBtA2dpParameters(AudioParameter &parameters) {
1097 TIME_CHECK();
1098 std::optional<bool> a2dpEnabled;
1099 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1100 parameters, String8(AudioParameter::keyBtA2dpSuspended),
1101 [&a2dpEnabled](const String8& trueOrFalse) {
1102 if (trueOrFalse == AudioParameter::valueTrue) {
1103 a2dpEnabled = false; // 'suspended' == true
1104 return OK;
1105 } else if (trueOrFalse == AudioParameter::valueFalse) {
1106 a2dpEnabled = true; // 'suspended' == false
1107 return OK;
1108 }
1109 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1110 AudioParameter::keyBtA2dpSuspended, trueOrFalse.c_str());
1111 return BAD_VALUE;
1112 }));
1113 // FIXME(b/278976019): Support keyReconfigA2dp via vendor plugin
1114 if (mBluetoothA2dp != nullptr && a2dpEnabled.has_value()) {
1115 return statusTFromBinderStatus(mBluetoothA2dp->setEnabled(a2dpEnabled.value()));
1116 }
1117 return OK;
1118}
1119
1120status_t DeviceHalAidl::filterAndUpdateBtHfpParameters(AudioParameter &parameters) {
1121 TIME_CHECK();
1122 IBluetooth::HfpConfig hfpConfig;
1123 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1124 parameters, String8(AudioParameter::keyBtHfpEnable),
1125 [&hfpConfig](const String8& trueOrFalse) {
1126 if (trueOrFalse == AudioParameter::valueTrue) {
1127 hfpConfig.isEnabled = Boolean{ .value = true };
1128 return OK;
1129 } else if (trueOrFalse == AudioParameter::valueFalse) {
1130 hfpConfig.isEnabled = Boolean{ .value = false };
1131 return OK;
1132 }
1133 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1134 AudioParameter::keyBtHfpEnable, trueOrFalse.c_str());
1135 return BAD_VALUE;
1136 }));
1137 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1138 parameters, String8(AudioParameter::keyBtHfpSamplingRate),
1139 [&hfpConfig](int sampleRate) {
1140 return sampleRate > 0 ?
1141 hfpConfig.sampleRate = Int{ .value = sampleRate }, OK : BAD_VALUE;
1142 }));
1143 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1144 parameters, String8(AudioParameter::keyBtHfpVolume),
1145 [&hfpConfig](int volume0to15) {
1146 if (volume0to15 >= 0 && volume0to15 <= 15) {
1147 hfpConfig.volume = Float{ .value = volume0to15 / 15.0f };
1148 return OK;
1149 }
1150 return BAD_VALUE;
1151 }));
1152 if (mBluetooth != nullptr && hfpConfig != IBluetooth::HfpConfig{}) {
1153 IBluetooth::HfpConfig newHfpConfig;
1154 return statusTFromBinderStatus(mBluetooth->setHfpConfig(hfpConfig, &newHfpConfig));
1155 }
1156 return OK;
1157}
1158
1159status_t DeviceHalAidl::filterAndUpdateBtLeParameters(AudioParameter &parameters) {
1160 TIME_CHECK();
1161 std::optional<bool> leEnabled;
1162 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1163 parameters, String8(AudioParameter::keyBtLeSuspended),
1164 [&leEnabled](const String8& trueOrFalse) {
1165 if (trueOrFalse == AudioParameter::valueTrue) {
1166 leEnabled = false; // 'suspended' == true
1167 return OK;
1168 } else if (trueOrFalse == AudioParameter::valueFalse) {
1169 leEnabled = true; // 'suspended' == false
1170 return OK;
1171 }
1172 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1173 AudioParameter::keyBtLeSuspended, trueOrFalse.c_str());
1174 return BAD_VALUE;
1175 }));
1176 if (mBluetoothLe != nullptr && leEnabled.has_value()) {
1177 return statusTFromBinderStatus(mBluetoothLe->setEnabled(leEnabled.value()));
1178 }
1179 return OK;
1180}
1181
1182status_t DeviceHalAidl::filterAndUpdateBtScoParameters(AudioParameter &parameters) {
1183 TIME_CHECK();
1184 IBluetooth::ScoConfig scoConfig;
1185 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1186 parameters, String8(AudioParameter::keyBtSco),
1187 [&scoConfig](const String8& onOrOff) {
1188 if (onOrOff == AudioParameter::valueOn) {
1189 scoConfig.isEnabled = Boolean{ .value = true };
1190 return OK;
1191 } else if (onOrOff == AudioParameter::valueOff) {
1192 scoConfig.isEnabled = Boolean{ .value = false };
1193 return OK;
1194 }
1195 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1196 AudioParameter::keyBtSco, onOrOff.c_str());
1197 return BAD_VALUE;
1198 }));
1199 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1200 parameters, String8(AudioParameter::keyBtScoHeadsetName),
1201 [&scoConfig](const String8& name) {
1202 scoConfig.debugName = name;
1203 return OK;
1204 }));
1205 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1206 parameters, String8(AudioParameter::keyBtNrec),
1207 [&scoConfig](const String8& onOrOff) {
1208 if (onOrOff == AudioParameter::valueOn) {
1209 scoConfig.isNrecEnabled = Boolean{ .value = true };
1210 return OK;
1211 } else if (onOrOff == AudioParameter::valueOff) {
1212 scoConfig.isNrecEnabled = Boolean{ .value = false };
1213 return OK;
1214 }
1215 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1216 AudioParameter::keyBtNrec, onOrOff.c_str());
1217 return BAD_VALUE;
1218 }));
1219 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1220 parameters, String8(AudioParameter::keyBtScoWb),
1221 [&scoConfig](const String8& onOrOff) {
1222 if (onOrOff == AudioParameter::valueOn) {
1223 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO_WB;
1224 return OK;
1225 } else if (onOrOff == AudioParameter::valueOff) {
1226 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO;
1227 return OK;
1228 }
1229 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1230 AudioParameter::keyBtScoWb, onOrOff.c_str());
1231 return BAD_VALUE;
1232 }));
1233 if (mBluetooth != nullptr && scoConfig != IBluetooth::ScoConfig{}) {
1234 IBluetooth::ScoConfig newScoConfig;
1235 return statusTFromBinderStatus(mBluetooth->setScoConfig(scoConfig, &newScoConfig));
1236 }
1237 return OK;
1238}
1239
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001240status_t DeviceHalAidl::findOrCreatePatch(
1241 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
1242 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
1243 requestedPatch.sourcePortConfigIds.end());
1244 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
1245 requestedPatch.sinkPortConfigIds.end());
1246 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
1247}
1248
1249status_t DeviceHalAidl::findOrCreatePatch(
1250 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
1251 AudioPatch* patch, bool* created) {
1252 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
1253 if (patchIt == mPatches.end()) {
1254 TIME_CHECK();
1255 AudioPatch requestedPatch, appliedPatch;
1256 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
1257 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
1258 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
1259 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
1260 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
1261 requestedPatch, &appliedPatch)));
1262 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
1263 *created = true;
1264 } else {
1265 *created = false;
1266 }
1267 *patch = patchIt->second;
1268 return OK;
1269}
1270
jiabin9c07faf2023-04-26 22:00:44 +00001271status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device, const AudioConfig* config,
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001272 AudioPortConfig* portConfig, bool* created) {
1273 auto portConfigIt = findPortConfig(device);
1274 if (portConfigIt == mPortConfigs.end()) {
1275 auto portsIt = findPort(device);
1276 if (portsIt == mPorts.end()) {
1277 ALOGE("%s: device port for device %s is not found in the module %s",
1278 __func__, device.toString().c_str(), mInstance.c_str());
1279 return BAD_VALUE;
1280 }
1281 AudioPortConfig requestedPortConfig;
1282 requestedPortConfig.portId = portsIt->first;
jiabin9c07faf2023-04-26 22:00:44 +00001283 if (config != nullptr) {
1284 setPortConfigFromConfig(&requestedPortConfig, *config);
1285 }
David Lia8675d42023-03-30 21:08:06 +08001286 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1287 created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001288 } else {
1289 *created = false;
1290 }
1291 *portConfig = portConfigIt->second;
1292 return OK;
1293}
1294
1295status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001296 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001297 AudioSource source, const std::set<int32_t>& destinationPortIds,
1298 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001299 // These flags get removed one by one in this order when retrying port finding.
1300 static const std::vector<AudioInputFlags> kOptionalInputFlags{
1301 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001302 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001303 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001304 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
1305 AudioIoFlags matchFlags = flags.value();
Mikhail Naganov289468a2023-03-29 10:06:15 -07001306 auto portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001307 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
1308 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
1309 if (!isBitPositionFlagSet(
1310 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
1311 ++optionalInputFlagsIt;
1312 continue;
1313 }
1314 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
1315 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
Mikhail Naganov289468a2023-03-29 10:06:15 -07001316 portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001317 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
1318 "retried with flags %s", __func__, config.toString().c_str(),
1319 flags.value().toString().c_str(), mInstance.c_str(),
1320 matchFlags.toString().c_str());
1321 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001322 if (portsIt == mPorts.end()) {
1323 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001324 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001325 mInstance.c_str());
1326 return BAD_VALUE;
1327 }
1328 AudioPortConfig requestedPortConfig;
1329 requestedPortConfig.portId = portsIt->first;
1330 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001331 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001332 if (matchFlags.getTag() == AudioIoFlags::Tag::input
1333 && source != AudioSource::SYS_RESERVED_INVALID) {
1334 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
1335 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
1336 }
David Lia8675d42023-03-30 21:08:06 +08001337 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1338 created));
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001339 } else if (!flags.has_value()) {
1340 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
1341 "and was not created as flags are not specified",
1342 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
1343 return BAD_VALUE;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001344 } else {
David Lia8675d42023-03-30 21:08:06 +08001345 AudioPortConfig requestedPortConfig = portConfigIt->second;
1346 if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
1347 AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
1348 if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
1349 source != AudioSource::SYS_RESERVED_INVALID) {
1350 mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
1351 }
1352 }
1353
1354 if (requestedPortConfig != portConfigIt->second) {
1355 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1356 created));
1357 } else {
1358 *created = false;
1359 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001360 }
1361 *portConfig = portConfigIt->second;
1362 return OK;
1363}
1364
1365status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001366 const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
1367 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001368 using Tag = AudioPortExt::Tag;
1369 if (requestedPortConfig.ext.getTag() == Tag::mix) {
1370 if (const auto& p = requestedPortConfig;
1371 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001372 !p.format.has_value()) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001373 ALOGW("%s: provided mix port config is not fully specified: %s",
1374 __func__, p.toString().c_str());
1375 return BAD_VALUE;
1376 }
1377 AudioConfig config;
1378 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001379 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
1380 AudioPortMixExtUseCase::Tag::source ?
1381 requestedPortConfig.ext.get<Tag::mix>().usecase.
1382 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001383 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001384 requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
1385 portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001386 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
1387 return findOrCreatePortConfig(
jiabin9c07faf2023-04-26 22:00:44 +00001388 requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
1389 portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001390 }
1391 ALOGW("%s: unsupported audio port config: %s",
1392 __func__, requestedPortConfig.toString().c_str());
1393 return BAD_VALUE;
1394}
1395
1396DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
1397 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
1398 return std::find_if(mPatches.begin(), mPatches.end(),
1399 [&](const auto& pair) {
1400 const auto& p = pair.second;
1401 std::set<int32_t> patchSrcs(
1402 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
1403 std::set<int32_t> patchSinks(
1404 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
1405 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
1406}
1407
1408DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001409 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1410 return mPorts.find(mDefaultInputPortId);
1411 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1412 return mPorts.find(mDefaultOutputPortId);
1413 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001414 return std::find_if(mPorts.begin(), mPorts.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001415 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001416}
1417
1418DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001419 const AudioConfig& config, const AudioIoFlags& flags,
1420 const std::set<int32_t>& destinationPortIds) {
Mikhail Naganove93a0862023-03-15 17:06:59 -07001421 auto belongsToProfile = [&config](const AudioProfile& prof) {
1422 return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
1423 (config.base.channelMask.getTag() == AudioChannelLayout::none ||
1424 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
1425 config.base.channelMask) != prof.channelMasks.end()) &&
1426 (config.base.sampleRate == 0 ||
1427 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
1428 config.base.sampleRate) != prof.sampleRates.end());
1429 };
jiabin9c07faf2023-04-26 22:00:44 +00001430 static const std::vector<AudioOutputFlags> kOptionalOutputFlags{AudioOutputFlags::BIT_PERFECT};
1431 int optionalFlags = 0;
1432 auto flagMatches = [&flags, &optionalFlags](const AudioIoFlags& portFlags) {
1433 // Ports should be able to match if the optional flags are not requested.
1434 return portFlags == flags ||
1435 (portFlags.getTag() == AudioIoFlags::Tag::output &&
1436 AudioIoFlags::make<AudioIoFlags::Tag::output>(
1437 portFlags.get<AudioIoFlags::Tag::output>() &
1438 ~optionalFlags) == flags);
1439 };
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001440 auto matcher = [&](const auto& pair) {
1441 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001442 return p.ext.getTag() == AudioPortExt::Tag::mix &&
jiabin9c07faf2023-04-26 22:00:44 +00001443 flagMatches(p.flags) &&
Mikhail Naganov289468a2023-03-29 10:06:15 -07001444 (destinationPortIds.empty() ||
1445 std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
1446 [&](const int32_t destId) { return mRoutingMatrix.count(
1447 std::make_pair(p.id, destId)) != 0; })) &&
Mikhail Naganove93a0862023-03-15 17:06:59 -07001448 (p.profiles.empty() ||
1449 std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
1450 p.profiles.end()); };
jiabin9c07faf2023-04-26 22:00:44 +00001451 auto result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1452 if (result == mPorts.end() && flags.getTag() == AudioIoFlags::Tag::output) {
1453 auto optionalOutputFlagsIt = kOptionalOutputFlags.begin();
1454 while (result == mPorts.end() && optionalOutputFlagsIt != kOptionalOutputFlags.end()) {
1455 if (isBitPositionFlagSet(
1456 flags.get<AudioIoFlags::Tag::output>(), *optionalOutputFlagsIt)) {
1457 // If the flag is set by the request, it must be matched.
1458 ++optionalOutputFlagsIt;
1459 continue;
1460 }
1461 optionalFlags |= makeBitPositionFlagMask(*optionalOutputFlagsIt++);
1462 result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1463 ALOGI("%s: port for config %s, flags %s was not found in the module %s, "
1464 "retried with excluding optional flags %#x", __func__, config.toString().c_str(),
1465 flags.toString().c_str(), mInstance.c_str(), optionalFlags);
1466 }
1467 }
1468 return result;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001469}
1470
1471DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001472 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001473 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001474}
1475
1476DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001477 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001478 using Tag = AudioPortExt::Tag;
1479 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
1480 [&](const auto& pair) {
1481 const auto& p = pair.second;
1482 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
1483 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
1484 !p.format.has_value() || !p.flags.has_value(),
1485 "%s: stored mix port config is not fully specified: %s",
1486 __func__, p.toString().c_str());
1487 return p.ext.getTag() == Tag::mix &&
1488 isConfigEqualToPortConfig(config, p) &&
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001489 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001490 p.ext.template get<Tag::mix>().handle == ioHandle; });
1491}
Mikhail Naganove93a0862023-03-15 17:06:59 -07001492
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001493void DeviceHalAidl::resetPatch(int32_t patchId) {
1494 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1495 mPatches.erase(it);
1496 TIME_CHECK();
1497 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1498 ALOGE("%s: error while resetting patch %d: %s",
1499 __func__, patchId, status.getDescription().c_str());
1500 }
1501 return;
1502 }
1503 ALOGE("%s: patch id %d not found", __func__, patchId);
1504}
1505
1506void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1507 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1508 mPortConfigs.erase(it);
1509 TIME_CHECK();
1510 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1511 !status.isOk()) {
1512 ALOGE("%s: error while resetting port config %d: %s",
1513 __func__, portConfigId, status.getDescription().c_str());
1514 }
1515 return;
1516 }
1517 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1518}
1519
Mikhail Naganove93a0862023-03-15 17:06:59 -07001520void DeviceHalAidl::resetUnusedPatches() {
1521 // Since patches can be created independently of streams via 'createAudioPatch',
1522 // here we only clean up patches for released streams.
1523 for (auto it = mStreams.begin(); it != mStreams.end(); ) {
1524 if (auto streamSp = it->first.promote(); streamSp) {
1525 ++it;
1526 } else {
1527 resetPatch(it->second);
1528 it = mStreams.erase(it);
1529 }
1530 }
1531}
1532
1533void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
1534 resetUnusedPatches();
1535 resetUnusedPortConfigs();
1536}
1537
1538void DeviceHalAidl::resetUnusedPortConfigs() {
1539 // The assumption is that port configs are used to create patches
1540 // (or to open streams, but that involves creation of patches, too). Thus,
1541 // orphaned port configs can and should be reset.
1542 std::set<int32_t> portConfigIds;
1543 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
1544 std::inserter(portConfigIds, portConfigIds.end()),
1545 [](const auto& pcPair) { return pcPair.first; });
1546 for (const auto& p : mPatches) {
1547 for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
1548 for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
1549 }
jiabin9c07faf2023-04-26 22:00:44 +00001550 for (int32_t id : mInitialPortConfigIds) {
1551 portConfigIds.erase(id);
1552 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001553 for (int32_t id : portConfigIds) resetPortConfig(id);
1554}
1555
Mikhail Naganov289468a2023-03-29 10:06:15 -07001556status_t DeviceHalAidl::updateRoutes() {
1557 TIME_CHECK();
Mikhail Naganov289468a2023-03-29 10:06:15 -07001558 RETURN_STATUS_IF_ERROR(
Mikhail Naganovf83b9742023-04-24 13:06:04 -07001559 statusTFromBinderStatus(mModule->getAudioRoutes(&mRoutes)));
1560 ALOGW_IF(mRoutes.empty(), "%s: module %s returned an empty list of audio routes",
Mikhail Naganov289468a2023-03-29 10:06:15 -07001561 __func__, mInstance.c_str());
1562 mRoutingMatrix.clear();
Mikhail Naganovf83b9742023-04-24 13:06:04 -07001563 for (const auto& r : mRoutes) {
Mikhail Naganov289468a2023-03-29 10:06:15 -07001564 for (auto portId : r.sourcePortIds) {
1565 mRoutingMatrix.emplace(r.sinkPortId, portId);
1566 mRoutingMatrix.emplace(portId, r.sinkPortId);
1567 }
1568 }
1569 return OK;
1570}
1571
Mikhail Naganovdfd594e2023-02-08 16:59:41 -08001572void DeviceHalAidl::clearCallbacks(void* cookie) {
1573 std::lock_guard l(mLock);
1574 mCallbacks.erase(cookie);
1575}
1576
1577sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1578 return getCallbackImpl(cookie, &Callbacks::out);
1579}
1580
1581void DeviceHalAidl::setStreamOutCallback(
1582 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1583 setCallbackImpl(cookie, &Callbacks::out, cb);
1584}
1585
1586sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1587 void* cookie) {
1588 return getCallbackImpl(cookie, &Callbacks::event);
1589}
1590
1591void DeviceHalAidl::setStreamOutEventCallback(
1592 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1593 setCallbackImpl(cookie, &Callbacks::event, cb);
1594}
1595
1596sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1597 void* cookie) {
1598 return getCallbackImpl(cookie, &Callbacks::latency);
1599}
1600
1601void DeviceHalAidl::setStreamOutLatencyModeCallback(
1602 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1603 setCallbackImpl(cookie, &Callbacks::latency, cb);
1604}
1605
1606template<class C>
1607sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1608 std::lock_guard l(mLock);
1609 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1610 return ((it->second).*field).promote();
1611 }
1612 return nullptr;
1613}
1614template<class C>
1615void DeviceHalAidl::setCallbackImpl(
1616 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1617 std::lock_guard l(mLock);
1618 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1619 (it->second).*field = cb;
1620 }
1621}
1622
Mikhail Naganov31d46652023-01-10 18:29:25 +00001623} // namespace android