blob: a4e1ff69a9f6c80244d5e20595622f1ba429b428 [file] [log] [blame]
Shunkai Yao51202502022-12-12 06:11:46 +00001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "DeviceHalAidl"
Vlad Popa03bd5bc2023-01-17 16:16:51 +010018// #define LOG_NDEBUG 0
Shunkai Yao51202502022-12-12 06:11:46 +000019
Mikhail Naganovf56ce782023-01-25 11:29:11 -080020#include <algorithm>
21#include <forward_list>
22
Mikhail Naganovb0c55252023-02-08 16:59:41 -080023#include <aidl/android/hardware/audio/core/BnStreamCallback.h>
24#include <aidl/android/hardware/audio/core/BnStreamOutEventCallback.h>
Mikhail Naganovfab697c2023-01-11 19:33:13 +000025#include <aidl/android/hardware/audio/core/StreamDescriptor.h>
26#include <error/expected_utils.h>
27#include <media/AidlConversionCppNdk.h>
Mikhail Naganovbfbb75b2023-04-21 18:48:16 -070028#include <media/AidlConversionNdkCpp.h>
Mikhail Naganovfab697c2023-01-11 19:33:13 +000029#include <media/AidlConversionUtil.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000030#include <mediautils/TimeCheck.h>
Mikhail Naganov8bd806e2023-01-30 12:33:18 -080031#include <Utils.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000032#include <utils/Log.h>
Shunkai Yao51202502022-12-12 06:11:46 +000033
Mikhail Naganov31d46652023-01-10 18:29:25 +000034#include "DeviceHalAidl.h"
35#include "StreamHalAidl.h"
36
Mikhail Naganovfab697c2023-01-11 19:33:13 +000037using aidl::android::aidl_utils::statusTFromBinderStatus;
Mikhail Naganov27382bb2023-04-27 18:14:15 -070038using aidl::android::media::audio::common::Boolean;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -070039using aidl::android::media::audio::common::AudioChannelLayout;
Mikhail Naganovf56ce782023-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 Naganov8bd806e2023-01-30 12:33:18 -080043using aidl::android::media::audio::common::AudioDeviceType;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -070044using aidl::android::media::audio::common::AudioFormatType;
Mikhail Naganov8bd806e2023-01-30 12:33:18 -080045using aidl::android::media::audio::common::AudioInputFlags;
Mikhail Naganovf56ce782023-01-25 11:29:11 -080046using aidl::android::media::audio::common::AudioIoFlags;
Mikhail Naganovb0c55252023-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 Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovb1ddbb02023-03-15 17:06:59 -070059using aidl::android::media::audio::common::AudioProfile;
Mikhail Naganovf56ce782023-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 Naganovb1ddbb02023-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 Naganovf56ce782023-01-25 11:29:11 -080069using aidl::android::hardware::audio::common::RecordTrackMetadata;
70using aidl::android::hardware::audio::core::AudioPatch;
Mikhail Naganovecfafb72023-03-29 10:06:15 -070071using aidl::android::hardware::audio::core::AudioRoute;
Mikhail Naganov27382bb2023-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 Naganovb1ddbb02023-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 Naganovf56ce782023-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 Naganov2d814892023-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;
111 return cpp;
112}
113
Mikhail Naganovffd97712023-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 Naganovf56ce782023-01-25 11:29:11 -0800126} // namespace
127
Mikhail Naganovffd97712023-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 Naganov27382bb2023-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 Naganovffd97712023-05-03 17:45:36 -0700135}
136
Mikhail Naganov2d814892023-04-24 13:06:04 -0700137status_t DeviceHalAidl::getAudioPorts(std::vector<media::audio::common::AudioPort> *ports) {
Mikhail Naganov741c3472023-05-05 17:36:39 -0700138 return ::aidl::android::convertContainer(mPorts, ports,
139 [](const Ports::value_type& pair) { return ndk2cpp_AudioPort(pair.second); });
Mikhail Naganov2d814892023-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 Naganovffd97712023-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 Naganovf56ce782023-01-25 11:29:11 -0800171 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000172 if (mModule == nullptr) return NO_INIT;
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800173 std::vector<AudioPort> ports;
Mikhail Naganov2d814892023-04-24 13:06:04 -0700174 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
Mikhail Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovecfafb72023-03-29 10:06:15 -0700194 RETURN_STATUS_IF_ERROR(updateRoutes());
Mikhail Naganovf56ce782023-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); });
jiabin2248fa12023-04-27 22:04:16 +0000201 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
202 std::inserter(mInitialPortConfigIds, mInitialPortConfigIds.end()),
203 [](const auto& pcPair) { return pcPair.first; });
Mikhail Naganovf56ce782023-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 Naganovffd97712023-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 Naganovffd97712023-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 Naganov27382bb2023-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 Naganov27382bb2023-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 }
Mikhail Naganovbaab5012023-05-31 14:24:48 -0700289 if (status_t status = filterAndUpdateScreenParameters(parameters); status != OK) {
290 ALOGW("%s: filtering or updating screen parameters failed: %d", __func__, status);
291 }
Mikhail Naganov27382bb2023-04-27 18:14:15 -0700292
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 Naganov27382bb2023-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 Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganov8bd806e2023-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 Naganovb1ddbb02023-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 Naganovb1ddbb02023-03-15 17:06:59 -0700356 &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov8bd806e2023-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 Naganovf56ce782023-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 Naganov8bd806e2023-01-30 12:33:18 -0800366 Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
Mikhail Naganovb1ddbb02023-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());
jiabin2248fa12023-04-27 22:04:16 +0000372 resetUnusedPatchesAndPortConfigs();
Mikhail Naganovf56ce782023-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;
jiabin2248fa12023-04-27 22:04:16 +0000378 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, aidlConfig,
379 &devicePortConfig, &created));
Mikhail Naganovf56ce782023-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 Naganovecfafb72023-03-29 10:06:15 -0700384 std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800385 if (created) {
386 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
387 }
388 setConfigFromPortConfig(aidlConfig, *mixPortConfig);
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800389 if (isInput) {
390 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700391 {devicePortConfig.id}, {mixPortConfig->id}, aidlPatch, &created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800392 } else {
393 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700394 {mixPortConfig->id}, {devicePortConfig.id}, aidlPatch, &created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800395 }
396 if (created) {
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700397 cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, aidlPatch->id);
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800398 }
399 if (aidlConfig->frameCount <= 0) {
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700400 aidlConfig->frameCount = aidlPatch->minimumStreamBufferSizeFrames;
Mikhail Naganovf56ce782023-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 Naganovb0c55252023-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 Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovf56ce782023-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 Naganovb1ddbb02023-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 Naganovb1ddbb02023-03-15 17:06:59 -0700549 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800550 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
551 args.portConfigId = mixPortConfig.id;
Mikhail Naganovb0c55252023-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 Naganovf56ce782023-01-25 11:29:11 -0800563 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovb0c55252023-02-08 16:59:41 -0800564 args.eventCallback = eventCb;
Mikhail Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovb1ddbb02023-03-15 17:06:59 -0700573 *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganovb0c55252023-02-08 16:59:41 -0800574 std::move(ret.stream), this /*callbackBroker*/);
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700575 mStreams.insert(std::pair(*outStream, aidlPatch.id));
Mikhail Naganovb0c55252023-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 Naganovf56ce782023-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 Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovf56ce782023-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 Naganovb1ddbb02023-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 Naganovb1ddbb02023-03-15 17:06:59 -0700614 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovb1ddbb02023-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 Naganovb1ddbb02023-03-15 17:06:59 -0700636 mStreams.insert(std::pair(*inStream, aidlPatch.id));
Mikhail Naganovf56ce782023-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 Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovf56ce782023-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 Naganovf56ce782023-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 Naganovf56ce782023-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 Naganovf56ce782023-01-25 11:29:11 -0800699 }
Mikhail Naganov8bd806e2023-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 Naganovf56ce782023-01-25 11:29:11 -0800703 auto fillPortConfigs = [&](
Mikhail Naganovecfafb72023-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 Naganovf56ce782023-01-25 11:29:11 -0800707 for (const auto& s : configs) {
708 AudioPortConfig portConfig;
709 bool created = false;
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700710 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
711 s, destinationPortIds, &portConfig, &created));
Mikhail Naganovf56ce782023-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 Naganovecfafb72023-03-29 10:06:15 -0700716 if (portIds != nullptr) {
717 portIds->insert(portConfig.portId);
718 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800719 }
720 return OK;
721 };
Mikhail Naganovecfafb72023-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 Naganovf56ce782023-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 Naganovf56ce782023-01-25 11:29:11 -0800749 }
750 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000751 return OK;
752}
753
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800754status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov8bd806e2023-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 Naganovf56ce782023-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 Naganovb1ddbb02023-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 Naganovb1ddbb02023-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 Naganovecfafb72023-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 Naganovbfbb75b2023-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
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100963status_t DeviceHalAidl::getSoundDoseInterface(const std::string& module,
964 ::ndk::SpAIBinder* soundDoseBinder) {
965 TIME_CHECK();
966 if (!mModule) return NO_INIT;
967 if (mSoundDose == nullptr) {
968 ndk::ScopedAStatus status = mModule->getSoundDose(&mSoundDose);
969 if (!status.isOk()) {
970 ALOGE("%s failed to return the sound dose interface for module %s: %s",
971 __func__,
972 module.c_str(),
973 status.getDescription().c_str());
974 return BAD_VALUE;
975 }
976 }
977 *soundDoseBinder = mSoundDose->asBinder();
978 ALOGI("%s using audio AIDL HAL sound dose interface", __func__);
979
980 return OK;
981}
982
jiabinc0048632023-04-27 22:04:31 +0000983status_t DeviceHalAidl::prepareToDisconnectExternalDevice(const struct audio_port_v7* port) {
984 // There is not AIDL API defined for `prepareToDisconnectExternalDevice`.
985 // Call `setConnectedState` instead.
986 // TODO(b/279824103): call prepareToDisconnectExternalDevice when it is added.
987 const status_t status = setConnectedState(port, false /*connected*/);
988 if (status == NO_ERROR) {
989 mDeviceDisconnectionNotified.insert(port->id);
990 }
991 return status;
992}
993
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700994status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
995 TIME_CHECK();
996 if (!mModule) return NO_INIT;
997 if (port == nullptr) {
998 return BAD_VALUE;
999 }
jiabinc0048632023-04-27 22:04:31 +00001000 if (!connected && mDeviceDisconnectionNotified.erase(port->id) > 0) {
1001 // For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
1002 // and then call `setConnectedState`. However, there is no API for
1003 // `prepareToDisconnectExternalDevice` yet. In that case, `setConnectedState` will be
1004 // called when calling `prepareToDisconnectExternalDevice`. Do not call to the HAL if
1005 // previous call is successful. Also remove the cache here to avoid a large cache after
1006 // a long run.
1007 return NO_ERROR;
1008 }
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001009 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
1010 ::aidl::android::AudioPortDirection::INPUT;
1011 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
1012 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
1013 if (aidlPort.ext.getTag() != AudioPortExt::device) {
1014 ALOGE("%s: provided port is not a device port (module %s): %s",
1015 __func__, mInstance.c_str(), aidlPort.toString().c_str());
1016 return BAD_VALUE;
1017 }
1018 if (connected) {
1019 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1020 // Reset the device address to find the "template" port.
1021 matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
1022 auto portsIt = findPort(matchDevice);
1023 if (portsIt == mPorts.end()) {
1024 ALOGW("%s: device port for device %s is not found in the module %s",
1025 __func__, matchDevice.toString().c_str(), mInstance.c_str());
1026 return BAD_VALUE;
1027 }
1028 // Use the ID of the "template" port, use all the information from the provided port.
1029 aidlPort.id = portsIt->first;
1030 AudioPort connectedPort;
1031 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
1032 aidlPort, &connectedPort)));
1033 const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
1034 LOG_ALWAYS_FATAL_IF(!inserted,
1035 "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
1036 __func__, mInstance.c_str(), connectedPort.toString().c_str(),
1037 it->second.toString().c_str());
1038 } else { // !connected
1039 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1040 auto portsIt = findPort(matchDevice);
1041 if (portsIt == mPorts.end()) {
1042 ALOGW("%s: device port for device %s is not found in the module %s",
1043 __func__, matchDevice.toString().c_str(), mInstance.c_str());
1044 return BAD_VALUE;
1045 }
1046 // Any streams opened on the external device must be closed by this time,
1047 // thus we can clean up patches and port configs that were created for them.
1048 resetUnusedPatchesAndPortConfigs();
1049 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
1050 portsIt->second.id)));
1051 mPorts.erase(portsIt);
1052 }
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001053 return updateRoutes();
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001054}
1055
1056status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
1057 TIME_CHECK();
1058 if (!mModule) return NO_INIT;
1059 ModuleDebug debug{ .simulateDeviceConnections = enabled };
1060 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
1061 // This is important to log as it affects HAL behavior.
1062 if (status == OK) {
1063 ALOGI("%s: set enabled: %d", __func__, enabled);
1064 } else {
1065 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
1066 }
1067 return status;
1068}
1069
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001070bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
1071 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1072 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1073}
1074
1075bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
1076 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1077 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1078 return p.portId == mDefaultInputPortId;
1079 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1080 return p.portId == mDefaultOutputPortId;
1081 }
1082 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1083}
1084
David Lia8f1e582023-03-30 21:08:06 +08001085status_t DeviceHalAidl::createOrUpdatePortConfig(
1086 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool* created) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001087 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001088 AudioPortConfig appliedPortConfig;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001089 bool applied = false;
1090 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001091 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001092 if (!applied) {
1093 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001094 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001095 if (!applied) {
1096 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001097 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001098 return NO_INIT;
1099 }
1100 }
David Lia8f1e582023-03-30 21:08:06 +08001101
1102 int32_t id = appliedPortConfig.id;
1103 if (requestedPortConfig.id != 0 && requestedPortConfig.id != id) {
1104 LOG_ALWAYS_FATAL("%s: requested port config id %d changed to %d", __func__,
1105 requestedPortConfig.id, id);
1106 }
1107
1108 auto [it, inserted] = mPortConfigs.insert_or_assign(std::move(id),
1109 std::move(appliedPortConfig));
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001110 *result = it;
David Lia8f1e582023-03-30 21:08:06 +08001111 *created = inserted;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001112 return OK;
1113}
1114
Mikhail Naganov27382bb2023-04-27 18:14:15 -07001115status_t DeviceHalAidl::filterAndUpdateBtA2dpParameters(AudioParameter &parameters) {
1116 TIME_CHECK();
1117 std::optional<bool> a2dpEnabled;
1118 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1119 parameters, String8(AudioParameter::keyBtA2dpSuspended),
1120 [&a2dpEnabled](const String8& trueOrFalse) {
1121 if (trueOrFalse == AudioParameter::valueTrue) {
1122 a2dpEnabled = false; // 'suspended' == true
1123 return OK;
1124 } else if (trueOrFalse == AudioParameter::valueFalse) {
1125 a2dpEnabled = true; // 'suspended' == false
1126 return OK;
1127 }
1128 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1129 AudioParameter::keyBtA2dpSuspended, trueOrFalse.c_str());
1130 return BAD_VALUE;
1131 }));
1132 // FIXME(b/278976019): Support keyReconfigA2dp via vendor plugin
1133 if (mBluetoothA2dp != nullptr && a2dpEnabled.has_value()) {
1134 return statusTFromBinderStatus(mBluetoothA2dp->setEnabled(a2dpEnabled.value()));
1135 }
1136 return OK;
1137}
1138
1139status_t DeviceHalAidl::filterAndUpdateBtHfpParameters(AudioParameter &parameters) {
1140 TIME_CHECK();
1141 IBluetooth::HfpConfig hfpConfig;
1142 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1143 parameters, String8(AudioParameter::keyBtHfpEnable),
1144 [&hfpConfig](const String8& trueOrFalse) {
1145 if (trueOrFalse == AudioParameter::valueTrue) {
1146 hfpConfig.isEnabled = Boolean{ .value = true };
1147 return OK;
1148 } else if (trueOrFalse == AudioParameter::valueFalse) {
1149 hfpConfig.isEnabled = Boolean{ .value = false };
1150 return OK;
1151 }
1152 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1153 AudioParameter::keyBtHfpEnable, trueOrFalse.c_str());
1154 return BAD_VALUE;
1155 }));
1156 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1157 parameters, String8(AudioParameter::keyBtHfpSamplingRate),
1158 [&hfpConfig](int sampleRate) {
1159 return sampleRate > 0 ?
1160 hfpConfig.sampleRate = Int{ .value = sampleRate }, OK : BAD_VALUE;
1161 }));
1162 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1163 parameters, String8(AudioParameter::keyBtHfpVolume),
1164 [&hfpConfig](int volume0to15) {
1165 if (volume0to15 >= 0 && volume0to15 <= 15) {
1166 hfpConfig.volume = Float{ .value = volume0to15 / 15.0f };
1167 return OK;
1168 }
1169 return BAD_VALUE;
1170 }));
1171 if (mBluetooth != nullptr && hfpConfig != IBluetooth::HfpConfig{}) {
1172 IBluetooth::HfpConfig newHfpConfig;
1173 return statusTFromBinderStatus(mBluetooth->setHfpConfig(hfpConfig, &newHfpConfig));
1174 }
1175 return OK;
1176}
1177
1178status_t DeviceHalAidl::filterAndUpdateBtLeParameters(AudioParameter &parameters) {
1179 TIME_CHECK();
1180 std::optional<bool> leEnabled;
1181 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1182 parameters, String8(AudioParameter::keyBtLeSuspended),
1183 [&leEnabled](const String8& trueOrFalse) {
1184 if (trueOrFalse == AudioParameter::valueTrue) {
1185 leEnabled = false; // 'suspended' == true
1186 return OK;
1187 } else if (trueOrFalse == AudioParameter::valueFalse) {
1188 leEnabled = true; // 'suspended' == false
1189 return OK;
1190 }
1191 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1192 AudioParameter::keyBtLeSuspended, trueOrFalse.c_str());
1193 return BAD_VALUE;
1194 }));
1195 if (mBluetoothLe != nullptr && leEnabled.has_value()) {
1196 return statusTFromBinderStatus(mBluetoothLe->setEnabled(leEnabled.value()));
1197 }
1198 return OK;
1199}
1200
1201status_t DeviceHalAidl::filterAndUpdateBtScoParameters(AudioParameter &parameters) {
1202 TIME_CHECK();
1203 IBluetooth::ScoConfig scoConfig;
1204 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1205 parameters, String8(AudioParameter::keyBtSco),
1206 [&scoConfig](const String8& onOrOff) {
1207 if (onOrOff == AudioParameter::valueOn) {
1208 scoConfig.isEnabled = Boolean{ .value = true };
1209 return OK;
1210 } else if (onOrOff == AudioParameter::valueOff) {
1211 scoConfig.isEnabled = Boolean{ .value = false };
1212 return OK;
1213 }
1214 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1215 AudioParameter::keyBtSco, onOrOff.c_str());
1216 return BAD_VALUE;
1217 }));
1218 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1219 parameters, String8(AudioParameter::keyBtScoHeadsetName),
1220 [&scoConfig](const String8& name) {
1221 scoConfig.debugName = name;
1222 return OK;
1223 }));
1224 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1225 parameters, String8(AudioParameter::keyBtNrec),
1226 [&scoConfig](const String8& onOrOff) {
1227 if (onOrOff == AudioParameter::valueOn) {
1228 scoConfig.isNrecEnabled = Boolean{ .value = true };
1229 return OK;
1230 } else if (onOrOff == AudioParameter::valueOff) {
1231 scoConfig.isNrecEnabled = Boolean{ .value = false };
1232 return OK;
1233 }
1234 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1235 AudioParameter::keyBtNrec, onOrOff.c_str());
1236 return BAD_VALUE;
1237 }));
1238 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1239 parameters, String8(AudioParameter::keyBtScoWb),
1240 [&scoConfig](const String8& onOrOff) {
1241 if (onOrOff == AudioParameter::valueOn) {
1242 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO_WB;
1243 return OK;
1244 } else if (onOrOff == AudioParameter::valueOff) {
1245 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO;
1246 return OK;
1247 }
1248 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1249 AudioParameter::keyBtScoWb, onOrOff.c_str());
1250 return BAD_VALUE;
1251 }));
1252 if (mBluetooth != nullptr && scoConfig != IBluetooth::ScoConfig{}) {
1253 IBluetooth::ScoConfig newScoConfig;
1254 return statusTFromBinderStatus(mBluetooth->setScoConfig(scoConfig, &newScoConfig));
1255 }
1256 return OK;
1257}
1258
Mikhail Naganovbaab5012023-05-31 14:24:48 -07001259status_t DeviceHalAidl::filterAndUpdateScreenParameters(AudioParameter &parameters) {
1260 TIME_CHECK();
1261 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1262 parameters, String8(AudioParameter::keyScreenState),
1263 [&](const String8& onOrOff) -> status_t {
1264 std::optional<bool> isTurnedOn;
1265 if (onOrOff == AudioParameter::valueOn) {
1266 isTurnedOn = true;
1267 } else if (onOrOff == AudioParameter::valueOff) {
1268 isTurnedOn = false;
1269 }
1270 if (!isTurnedOn.has_value()) {
1271 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1272 AudioParameter::keyScreenState, onOrOff.c_str());
1273 return BAD_VALUE;
1274 }
1275 return statusTFromBinderStatus(
1276 mModule->updateScreenState(isTurnedOn.value()));
1277 }));
1278 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1279 parameters, String8(AudioParameter::keyScreenRotation),
1280 [&](int rotationDegrees) -> status_t {
1281 IModule::ScreenRotation rotation;
1282 switch (rotationDegrees) {
1283 case 0: rotation = IModule::ScreenRotation::DEG_0; break;
1284 case 90: rotation = IModule::ScreenRotation::DEG_90; break;
1285 case 180: rotation = IModule::ScreenRotation::DEG_180; break;
1286 case 270: rotation = IModule::ScreenRotation::DEG_270; break;
1287 default:
1288 ALOGE("setParameters: parameter key \"%s\" has invalid value %d",
1289 AudioParameter::keyScreenRotation, rotationDegrees);
1290 return BAD_VALUE;
1291 }
1292 return statusTFromBinderStatus(mModule->updateScreenRotation(rotation));
1293 }));
1294 return OK;
1295}
1296
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001297status_t DeviceHalAidl::findOrCreatePatch(
1298 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
1299 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
1300 requestedPatch.sourcePortConfigIds.end());
1301 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
1302 requestedPatch.sinkPortConfigIds.end());
1303 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
1304}
1305
1306status_t DeviceHalAidl::findOrCreatePatch(
1307 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
1308 AudioPatch* patch, bool* created) {
1309 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
1310 if (patchIt == mPatches.end()) {
1311 TIME_CHECK();
1312 AudioPatch requestedPatch, appliedPatch;
1313 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
1314 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
1315 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
1316 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
1317 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
1318 requestedPatch, &appliedPatch)));
1319 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
1320 *created = true;
1321 } else {
1322 *created = false;
1323 }
1324 *patch = patchIt->second;
1325 return OK;
1326}
1327
jiabin2248fa12023-04-27 22:04:16 +00001328status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device, const AudioConfig* config,
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001329 AudioPortConfig* portConfig, bool* created) {
1330 auto portConfigIt = findPortConfig(device);
1331 if (portConfigIt == mPortConfigs.end()) {
1332 auto portsIt = findPort(device);
1333 if (portsIt == mPorts.end()) {
1334 ALOGE("%s: device port for device %s is not found in the module %s",
1335 __func__, device.toString().c_str(), mInstance.c_str());
1336 return BAD_VALUE;
1337 }
1338 AudioPortConfig requestedPortConfig;
1339 requestedPortConfig.portId = portsIt->first;
jiabin2248fa12023-04-27 22:04:16 +00001340 if (config != nullptr) {
1341 setPortConfigFromConfig(&requestedPortConfig, *config);
1342 }
David Lia8f1e582023-03-30 21:08:06 +08001343 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1344 created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001345 } else {
1346 *created = false;
1347 }
1348 *portConfig = portConfigIt->second;
1349 return OK;
1350}
1351
1352status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001353 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001354 AudioSource source, const std::set<int32_t>& destinationPortIds,
1355 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001356 // These flags get removed one by one in this order when retrying port finding.
1357 static const std::vector<AudioInputFlags> kOptionalInputFlags{
1358 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001359 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001360 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001361 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
1362 AudioIoFlags matchFlags = flags.value();
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001363 auto portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001364 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
1365 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
1366 if (!isBitPositionFlagSet(
1367 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
1368 ++optionalInputFlagsIt;
1369 continue;
1370 }
1371 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
1372 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001373 portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001374 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
1375 "retried with flags %s", __func__, config.toString().c_str(),
1376 flags.value().toString().c_str(), mInstance.c_str(),
1377 matchFlags.toString().c_str());
1378 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001379 if (portsIt == mPorts.end()) {
1380 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001381 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001382 mInstance.c_str());
1383 return BAD_VALUE;
1384 }
1385 AudioPortConfig requestedPortConfig;
1386 requestedPortConfig.portId = portsIt->first;
1387 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001388 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001389 if (matchFlags.getTag() == AudioIoFlags::Tag::input
1390 && source != AudioSource::SYS_RESERVED_INVALID) {
1391 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
1392 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
1393 }
David Lia8f1e582023-03-30 21:08:06 +08001394 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1395 created));
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001396 } else if (!flags.has_value()) {
1397 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
1398 "and was not created as flags are not specified",
1399 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
1400 return BAD_VALUE;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001401 } else {
David Lia8f1e582023-03-30 21:08:06 +08001402 AudioPortConfig requestedPortConfig = portConfigIt->second;
1403 if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
1404 AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
1405 if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
1406 source != AudioSource::SYS_RESERVED_INVALID) {
1407 mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
1408 }
1409 }
1410
1411 if (requestedPortConfig != portConfigIt->second) {
1412 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1413 created));
1414 } else {
1415 *created = false;
1416 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001417 }
1418 *portConfig = portConfigIt->second;
1419 return OK;
1420}
1421
1422status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001423 const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
1424 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001425 using Tag = AudioPortExt::Tag;
1426 if (requestedPortConfig.ext.getTag() == Tag::mix) {
1427 if (const auto& p = requestedPortConfig;
1428 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001429 !p.format.has_value()) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001430 ALOGW("%s: provided mix port config is not fully specified: %s",
1431 __func__, p.toString().c_str());
1432 return BAD_VALUE;
1433 }
1434 AudioConfig config;
1435 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001436 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
1437 AudioPortMixExtUseCase::Tag::source ?
1438 requestedPortConfig.ext.get<Tag::mix>().usecase.
1439 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001440 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001441 requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
1442 portConfig, created);
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001443 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
1444 return findOrCreatePortConfig(
jiabin2248fa12023-04-27 22:04:16 +00001445 requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
1446 portConfig, created);
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001447 }
1448 ALOGW("%s: unsupported audio port config: %s",
1449 __func__, requestedPortConfig.toString().c_str());
1450 return BAD_VALUE;
1451}
1452
1453DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
1454 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
1455 return std::find_if(mPatches.begin(), mPatches.end(),
1456 [&](const auto& pair) {
1457 const auto& p = pair.second;
1458 std::set<int32_t> patchSrcs(
1459 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
1460 std::set<int32_t> patchSinks(
1461 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
1462 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
1463}
1464
1465DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001466 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1467 return mPorts.find(mDefaultInputPortId);
1468 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1469 return mPorts.find(mDefaultOutputPortId);
1470 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001471 return std::find_if(mPorts.begin(), mPorts.end(),
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001472 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001473}
1474
1475DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001476 const AudioConfig& config, const AudioIoFlags& flags,
1477 const std::set<int32_t>& destinationPortIds) {
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001478 auto belongsToProfile = [&config](const AudioProfile& prof) {
1479 return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
1480 (config.base.channelMask.getTag() == AudioChannelLayout::none ||
1481 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
1482 config.base.channelMask) != prof.channelMasks.end()) &&
1483 (config.base.sampleRate == 0 ||
1484 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
1485 config.base.sampleRate) != prof.sampleRates.end());
1486 };
jiabin2248fa12023-04-27 22:04:16 +00001487 static const std::vector<AudioOutputFlags> kOptionalOutputFlags{AudioOutputFlags::BIT_PERFECT};
1488 int optionalFlags = 0;
1489 auto flagMatches = [&flags, &optionalFlags](const AudioIoFlags& portFlags) {
1490 // Ports should be able to match if the optional flags are not requested.
1491 return portFlags == flags ||
1492 (portFlags.getTag() == AudioIoFlags::Tag::output &&
1493 AudioIoFlags::make<AudioIoFlags::Tag::output>(
1494 portFlags.get<AudioIoFlags::Tag::output>() &
1495 ~optionalFlags) == flags);
1496 };
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001497 auto matcher = [&](const auto& pair) {
1498 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001499 return p.ext.getTag() == AudioPortExt::Tag::mix &&
jiabin2248fa12023-04-27 22:04:16 +00001500 flagMatches(p.flags) &&
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001501 (destinationPortIds.empty() ||
1502 std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
1503 [&](const int32_t destId) { return mRoutingMatrix.count(
1504 std::make_pair(p.id, destId)) != 0; })) &&
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001505 (p.profiles.empty() ||
1506 std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
1507 p.profiles.end()); };
jiabin2248fa12023-04-27 22:04:16 +00001508 auto result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1509 if (result == mPorts.end() && flags.getTag() == AudioIoFlags::Tag::output) {
1510 auto optionalOutputFlagsIt = kOptionalOutputFlags.begin();
1511 while (result == mPorts.end() && optionalOutputFlagsIt != kOptionalOutputFlags.end()) {
1512 if (isBitPositionFlagSet(
1513 flags.get<AudioIoFlags::Tag::output>(), *optionalOutputFlagsIt)) {
1514 // If the flag is set by the request, it must be matched.
1515 ++optionalOutputFlagsIt;
1516 continue;
1517 }
1518 optionalFlags |= makeBitPositionFlagMask(*optionalOutputFlagsIt++);
1519 result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1520 ALOGI("%s: port for config %s, flags %s was not found in the module %s, "
1521 "retried with excluding optional flags %#x", __func__, config.toString().c_str(),
1522 flags.toString().c_str(), mInstance.c_str(), optionalFlags);
1523 }
1524 }
1525 return result;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001526}
1527
1528DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001529 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001530 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001531}
1532
1533DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001534 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001535 using Tag = AudioPortExt::Tag;
1536 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
1537 [&](const auto& pair) {
1538 const auto& p = pair.second;
1539 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
1540 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
1541 !p.format.has_value() || !p.flags.has_value(),
1542 "%s: stored mix port config is not fully specified: %s",
1543 __func__, p.toString().c_str());
1544 return p.ext.getTag() == Tag::mix &&
1545 isConfigEqualToPortConfig(config, p) &&
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001546 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001547 p.ext.template get<Tag::mix>().handle == ioHandle; });
1548}
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001549
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001550void DeviceHalAidl::resetPatch(int32_t patchId) {
1551 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1552 mPatches.erase(it);
1553 TIME_CHECK();
1554 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1555 ALOGE("%s: error while resetting patch %d: %s",
1556 __func__, patchId, status.getDescription().c_str());
1557 }
1558 return;
1559 }
1560 ALOGE("%s: patch id %d not found", __func__, patchId);
1561}
1562
1563void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1564 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1565 mPortConfigs.erase(it);
1566 TIME_CHECK();
1567 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1568 !status.isOk()) {
1569 ALOGE("%s: error while resetting port config %d: %s",
1570 __func__, portConfigId, status.getDescription().c_str());
1571 }
1572 return;
1573 }
1574 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1575}
1576
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001577void DeviceHalAidl::resetUnusedPatches() {
1578 // Since patches can be created independently of streams via 'createAudioPatch',
1579 // here we only clean up patches for released streams.
1580 for (auto it = mStreams.begin(); it != mStreams.end(); ) {
1581 if (auto streamSp = it->first.promote(); streamSp) {
1582 ++it;
1583 } else {
1584 resetPatch(it->second);
1585 it = mStreams.erase(it);
1586 }
1587 }
1588}
1589
1590void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
1591 resetUnusedPatches();
1592 resetUnusedPortConfigs();
1593}
1594
1595void DeviceHalAidl::resetUnusedPortConfigs() {
1596 // The assumption is that port configs are used to create patches
1597 // (or to open streams, but that involves creation of patches, too). Thus,
1598 // orphaned port configs can and should be reset.
1599 std::set<int32_t> portConfigIds;
1600 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
1601 std::inserter(portConfigIds, portConfigIds.end()),
1602 [](const auto& pcPair) { return pcPair.first; });
1603 for (const auto& p : mPatches) {
1604 for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
1605 for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
1606 }
jiabin2248fa12023-04-27 22:04:16 +00001607 for (int32_t id : mInitialPortConfigIds) {
1608 portConfigIds.erase(id);
1609 }
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001610 for (int32_t id : portConfigIds) resetPortConfig(id);
1611}
1612
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001613status_t DeviceHalAidl::updateRoutes() {
1614 TIME_CHECK();
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001615 RETURN_STATUS_IF_ERROR(
Mikhail Naganov2d814892023-04-24 13:06:04 -07001616 statusTFromBinderStatus(mModule->getAudioRoutes(&mRoutes)));
1617 ALOGW_IF(mRoutes.empty(), "%s: module %s returned an empty list of audio routes",
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001618 __func__, mInstance.c_str());
1619 mRoutingMatrix.clear();
Mikhail Naganov2d814892023-04-24 13:06:04 -07001620 for (const auto& r : mRoutes) {
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001621 for (auto portId : r.sourcePortIds) {
1622 mRoutingMatrix.emplace(r.sinkPortId, portId);
1623 mRoutingMatrix.emplace(portId, r.sinkPortId);
1624 }
1625 }
1626 return OK;
1627}
1628
Mikhail Naganovb0c55252023-02-08 16:59:41 -08001629void DeviceHalAidl::clearCallbacks(void* cookie) {
1630 std::lock_guard l(mLock);
1631 mCallbacks.erase(cookie);
1632}
1633
1634sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1635 return getCallbackImpl(cookie, &Callbacks::out);
1636}
1637
1638void DeviceHalAidl::setStreamOutCallback(
1639 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1640 setCallbackImpl(cookie, &Callbacks::out, cb);
1641}
1642
1643sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1644 void* cookie) {
1645 return getCallbackImpl(cookie, &Callbacks::event);
1646}
1647
1648void DeviceHalAidl::setStreamOutEventCallback(
1649 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1650 setCallbackImpl(cookie, &Callbacks::event, cb);
1651}
1652
1653sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1654 void* cookie) {
1655 return getCallbackImpl(cookie, &Callbacks::latency);
1656}
1657
1658void DeviceHalAidl::setStreamOutLatencyModeCallback(
1659 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1660 setCallbackImpl(cookie, &Callbacks::latency, cb);
1661}
1662
1663template<class C>
1664sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1665 std::lock_guard l(mLock);
1666 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1667 return ((it->second).*field).promote();
1668 }
1669 return nullptr;
1670}
1671template<class C>
1672void DeviceHalAidl::setCallbackImpl(
1673 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1674 std::lock_guard l(mLock);
1675 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1676 (it->second).*field = cb;
1677 }
1678}
1679
Mikhail Naganov31d46652023-01-10 18:29:25 +00001680} // namespace android