blob: 06c5f53fb538ac0fa2174a1bfc90fa3399cd0012 [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 Naganove1253972023-05-25 17:36:48 -070065using aidl::android::media::audio::IHalAdapterVendorExtension;
Mikhail Naganov6352e822023-03-09 18:22:36 -080066using aidl::android::hardware::audio::common::getFrameSizeInBytes;
67using aidl::android::hardware::audio::common::isBitPositionFlagSet;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -070068using aidl::android::hardware::audio::common::isDefaultAudioFormat;
Mikhail Naganov6352e822023-03-09 18:22:36 -080069using aidl::android::hardware::audio::common::makeBitPositionFlagMask;
Mikhail Naganovf56ce782023-01-25 11:29:11 -080070using aidl::android::hardware::audio::common::RecordTrackMetadata;
71using aidl::android::hardware::audio::core::AudioPatch;
Mikhail Naganovecfafb72023-03-29 10:06:15 -070072using aidl::android::hardware::audio::core::AudioRoute;
Mikhail Naganov27382bb2023-04-27 18:14:15 -070073using aidl::android::hardware::audio::core::IBluetooth;
74using aidl::android::hardware::audio::core::IBluetoothA2dp;
75using aidl::android::hardware::audio::core::IBluetoothLe;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000076using aidl::android::hardware::audio::core::IModule;
77using aidl::android::hardware::audio::core::ITelephony;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -070078using aidl::android::hardware::audio::core::ModuleDebug;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000079using aidl::android::hardware::audio::core::StreamDescriptor;
Mikhail Naganove1253972023-05-25 17:36:48 -070080using aidl::android::hardware::audio::core::VendorParameter;
Mikhail Naganov31d46652023-01-10 18:29:25 +000081
82namespace android {
83
Mikhail Naganovf56ce782023-01-25 11:29:11 -080084namespace {
85
86bool isConfigEqualToPortConfig(const AudioConfig& config, const AudioPortConfig& portConfig) {
87 return portConfig.sampleRate.value().value == config.base.sampleRate &&
88 portConfig.channelMask.value() == config.base.channelMask &&
89 portConfig.format.value() == config.base.format;
90}
91
92void setConfigFromPortConfig(AudioConfig* config, const AudioPortConfig& portConfig) {
93 config->base.sampleRate = portConfig.sampleRate.value().value;
94 config->base.channelMask = portConfig.channelMask.value();
95 config->base.format = portConfig.format.value();
96}
97
98void setPortConfigFromConfig(AudioPortConfig* portConfig, const AudioConfig& config) {
99 portConfig->sampleRate = Int{ .value = config.base.sampleRate };
100 portConfig->channelMask = config.base.channelMask;
101 portConfig->format = config.base.format;
102}
103
Mikhail Naganov2d814892023-04-24 13:06:04 -0700104// Note: these converters are for types defined in different AIDL files. Although these
105// AIDL files are copies of each other, however formally these are different types
106// thus we don't use a conversion via a parcelable.
107ConversionResult<media::AudioRoute> ndk2cpp_AudioRoute(const AudioRoute& ndk) {
108 media::AudioRoute cpp;
109 cpp.sourcePortIds.insert(
110 cpp.sourcePortIds.end(), ndk.sourcePortIds.begin(), ndk.sourcePortIds.end());
111 cpp.sinkPortId = ndk.sinkPortId;
112 cpp.isExclusive = ndk.isExclusive;
113 return cpp;
114}
115
Mikhail Naganovffd97712023-05-03 17:45:36 -0700116template<typename T>
117std::shared_ptr<T> retrieveSubInterface(const std::shared_ptr<IModule>& module,
118 ::ndk::ScopedAStatus (IModule::*getT)(std::shared_ptr<T>*)) {
119 if (module != nullptr) {
120 std::shared_ptr<T> instance;
121 if (auto status = (module.get()->*getT)(&instance); status.isOk()) {
122 return instance;
123 }
124 }
125 return nullptr;
126}
127
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800128} // namespace
129
Mikhail Naganove1253972023-05-25 17:36:48 -0700130DeviceHalAidl::DeviceHalAidl(const std::string& instance, const std::shared_ptr<IModule>& module,
131 const std::shared_ptr<IHalAdapterVendorExtension>& vext)
Mikhail Naganovffd97712023-05-03 17:45:36 -0700132 : ConversionHelperAidl("DeviceHalAidl"),
Mikhail Naganove1253972023-05-25 17:36:48 -0700133 mInstance(instance), mModule(module), mVendorExt(vext),
Mikhail Naganov27382bb2023-04-27 18:14:15 -0700134 mTelephony(retrieveSubInterface<ITelephony>(module, &IModule::getTelephony)),
135 mBluetooth(retrieveSubInterface<IBluetooth>(module, &IModule::getBluetooth)),
136 mBluetoothA2dp(retrieveSubInterface<IBluetoothA2dp>(module, &IModule::getBluetoothA2dp)),
137 mBluetoothLe(retrieveSubInterface<IBluetoothLe>(module, &IModule::getBluetoothLe)) {
Mikhail Naganovffd97712023-05-03 17:45:36 -0700138}
139
Mikhail Naganov2d814892023-04-24 13:06:04 -0700140status_t DeviceHalAidl::getAudioPorts(std::vector<media::audio::common::AudioPort> *ports) {
Mikhail Naganov741c3472023-05-05 17:36:39 -0700141 return ::aidl::android::convertContainer(mPorts, ports,
142 [](const Ports::value_type& pair) { return ndk2cpp_AudioPort(pair.second); });
Mikhail Naganov2d814892023-04-24 13:06:04 -0700143}
144
145status_t DeviceHalAidl::getAudioRoutes(std::vector<media::AudioRoute> *routes) {
146 *routes = VALUE_OR_RETURN_STATUS(
147 ::aidl::android::convertContainer<std::vector<media::AudioRoute>>(
148 mRoutes, ndk2cpp_AudioRoute));
149 return OK;
150}
151
Mikhail Naganovffd97712023-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 Naganovf56ce782023-01-25 11:29:11 -0800174 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000175 if (mModule == nullptr) return NO_INIT;
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800176 std::vector<AudioPort> ports;
Mikhail Naganov2d814892023-04-24 13:06:04 -0700177 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
Mikhail Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovecfafb72023-03-29 10:06:15 -0700197 RETURN_STATUS_IF_ERROR(updateRoutes());
Mikhail Naganovf56ce782023-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); });
jiabin2248fa12023-04-27 22:04:16 +0000204 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
205 std::inserter(mInitialPortConfigIds, mInitialPortConfigIds.end()),
206 [](const auto& pcPair) { return pcPair.first; });
Mikhail Naganovf56ce782023-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 Naganovffd97712023-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 Naganovffd97712023-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 Naganov27382bb2023-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 Naganov27382bb2023-04-27 18:14:15 -0700277 AudioParameter parameters(kvPairs);
278 ALOGD("%s: parameters: \"%s\"", __func__, parameters.toString().c_str());
279
280 if (status_t status = filterAndUpdateBtA2dpParameters(parameters); status != OK) {
281 ALOGW("%s: filtering or updating BT A2DP parameters failed: %d", __func__, status);
282 }
283 if (status_t status = filterAndUpdateBtHfpParameters(parameters); status != OK) {
284 ALOGW("%s: filtering or updating BT HFP parameters failed: %d", __func__, status);
285 }
286 if (status_t status = filterAndUpdateBtLeParameters(parameters); status != OK) {
287 ALOGW("%s: filtering or updating BT LE parameters failed: %d", __func__, status);
288 }
289 if (status_t status = filterAndUpdateBtScoParameters(parameters); status != OK) {
290 ALOGW("%s: filtering or updating BT SCO parameters failed: %d", __func__, status);
291 }
Mikhail Naganovbaab5012023-05-31 14:24:48 -0700292 if (status_t status = filterAndUpdateScreenParameters(parameters); status != OK) {
293 ALOGW("%s: filtering or updating screen parameters failed: %d", __func__, status);
294 }
Mikhail Naganove1253972023-05-25 17:36:48 -0700295 return parseAndSetVendorParameters(mVendorExt, mModule, parameters);
Shunkai Yao51202502022-12-12 06:11:46 +0000296}
297
Mikhail Naganove1253972023-05-25 17:36:48 -0700298status_t DeviceHalAidl::getParameters(const String8& keys, String8 *values) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000299 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000300 if (!mModule) return NO_INIT;
Mikhail Naganove1253972023-05-25 17:36:48 -0700301 if (values == nullptr) {
302 return BAD_VALUE;
303 }
304 AudioParameter parameterKeys(keys), result;
305 if (status_t status = filterAndRetrieveBtA2dpParameters(parameterKeys, &result); status != OK) {
306 ALOGW("%s: filtering or retrieving BT A2DP parameters failed: %d", __func__, status);
307 }
308 *values = result.toString();
309 return parseAndGetVendorParameters(mVendorExt, mModule, parameterKeys, values);
Shunkai Yao51202502022-12-12 06:11:46 +0000310}
311
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800312namespace {
313
314class Cleanup {
315 public:
316 typedef void (DeviceHalAidl::*Cleaner)(int32_t);
317
318 Cleanup(DeviceHalAidl* device, Cleaner cleaner, int32_t id) :
319 mDevice(device), mCleaner(cleaner), mId(id) {}
320 ~Cleanup() { clean(); }
321 void clean() {
322 if (mDevice != nullptr) (mDevice->*mCleaner)(mId);
323 disarm();
324 }
325 void disarm() { mDevice = nullptr; }
326
327 private:
328 DeviceHalAidl* mDevice;
329 const Cleaner mCleaner;
330 const int32_t mId;
331};
332
333} // namespace
334
335// Since the order of container elements destruction is unspecified,
336// ensure that cleanups are performed from the most recent one and upwards.
337// This is the same as if there were individual Cleanup instances on the stack,
338// however the bonus is that we can disarm all of them with just one statement.
339class DeviceHalAidl::Cleanups : public std::forward_list<Cleanup> {
340 public:
341 ~Cleanups() { for (auto& c : *this) c.clean(); }
342 void disarmAll() { for (auto& c : *this) c.disarm(); }
343};
344
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800345status_t DeviceHalAidl::getInputBufferSize(const struct audio_config* config, size_t* size) {
346 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
347 if (size == nullptr) return BAD_VALUE;
348 TIME_CHECK();
349 if (!mModule) return NO_INIT;
350 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
351 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
352 AudioDevice aidlDevice;
353 aidlDevice.type.type = AudioDeviceType::IN_DEFAULT;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800354 AudioSource aidlSource = AudioSource::DEFAULT;
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800355 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
356 AudioPortConfig mixPortConfig;
357 Cleanups cleanups;
358 audio_config writableConfig = *config;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700359 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800360 RETURN_STATUS_IF_ERROR(prepareToOpenStream(0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700361 &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800362 *size = aidlConfig.frameCount *
363 getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
364 // Do not disarm cleanups to release temporary port configs.
365 return OK;
366}
367
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800368status_t DeviceHalAidl::prepareToOpenStream(
369 int32_t aidlHandle, const AudioDevice& aidlDevice, const AudioIoFlags& aidlFlags,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800370 AudioSource aidlSource, struct audio_config* config,
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800371 Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700372 AudioPatch* aidlPatch) {
373 ALOGD("%p %s::%s: handle %d, device %s, flags %s, source %s, config %s, mix port config %s",
374 this, getClassName().c_str(), __func__, aidlHandle, aidlDevice.toString().c_str(),
375 aidlFlags.toString().c_str(), toString(aidlSource).c_str(),
376 aidlConfig->toString().c_str(), mixPortConfig->toString().c_str());
jiabin2248fa12023-04-27 22:04:16 +0000377 resetUnusedPatchesAndPortConfigs();
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800378 const bool isInput = aidlFlags.getTag() == AudioIoFlags::Tag::input;
379 // Find / create AudioPortConfigs for the device port and the mix port,
380 // then find / create a patch between them, and open a stream on the mix port.
381 AudioPortConfig devicePortConfig;
382 bool created = false;
jiabin2248fa12023-04-27 22:04:16 +0000383 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, aidlConfig,
384 &devicePortConfig, &created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800385 if (created) {
386 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
387 }
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800388 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*aidlConfig, aidlFlags, aidlHandle, aidlSource,
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700389 std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800390 if (created) {
391 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
392 }
393 setConfigFromPortConfig(aidlConfig, *mixPortConfig);
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800394 if (isInput) {
395 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700396 {devicePortConfig.id}, {mixPortConfig->id}, aidlPatch, &created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800397 } else {
398 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700399 {mixPortConfig->id}, {devicePortConfig.id}, aidlPatch, &created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800400 }
401 if (created) {
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700402 cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, aidlPatch->id);
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800403 }
404 if (aidlConfig->frameCount <= 0) {
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700405 aidlConfig->frameCount = aidlPatch->minimumStreamBufferSizeFrames;
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800406 }
407 *config = VALUE_OR_RETURN_STATUS(
408 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(*aidlConfig, isInput));
409 return OK;
410}
411
Mikhail Naganovb0c55252023-02-08 16:59:41 -0800412namespace {
413
414class StreamCallbackBase {
415 protected:
416 explicit StreamCallbackBase(const sp<CallbackBroker>& broker) : mBroker(broker) {}
417 public:
418 void* getCookie() const { return mCookie; }
419 void setCookie(void* cookie) { mCookie = cookie; }
420 sp<CallbackBroker> getBroker() const {
421 if (void* cookie = mCookie; cookie != nullptr) return mBroker.promote();
422 return nullptr;
423 }
424 private:
425 const wp<CallbackBroker> mBroker;
426 std::atomic<void*> mCookie;
427};
428
429template<class C>
430class StreamCallbackBaseHelper {
431 protected:
432 explicit StreamCallbackBaseHelper(const StreamCallbackBase& base) : mBase(base) {}
433 sp<C> getCb(const sp<CallbackBroker>& broker, void* cookie);
434 using CbRef = const sp<C>&;
435 ndk::ScopedAStatus runCb(const std::function<void(CbRef cb)>& f) {
436 if (auto cb = getCb(mBase.getBroker(), mBase.getCookie()); cb != nullptr) f(cb);
437 return ndk::ScopedAStatus::ok();
438 }
439 private:
440 const StreamCallbackBase& mBase;
441};
442
443template<>
444sp<StreamOutHalInterfaceCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>::getCb(
445 const sp<CallbackBroker>& broker, void* cookie) {
446 if (broker != nullptr) return broker->getStreamOutCallback(cookie);
447 return nullptr;
448}
449
450template<>
451sp<StreamOutHalInterfaceEventCallback>
452StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::getCb(
453 const sp<CallbackBroker>& broker, void* cookie) {
454 if (broker != nullptr) return broker->getStreamOutEventCallback(cookie);
455 return nullptr;
456}
457
458template<>
459sp<StreamOutHalInterfaceLatencyModeCallback>
460StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::getCb(
461 const sp<CallbackBroker>& broker, void* cookie) {
462 if (broker != nullptr) return broker->getStreamOutLatencyModeCallback(cookie);
463 return nullptr;
464}
465
466/*
467Note on the callback ownership.
468
469In the Binder ownership model, the server implementation is kept alive
470as long as there is any client (proxy object) alive. This is done by
471incrementing the refcount of the server-side object by the Binder framework.
472When it detects that the last client is gone, it decrements the refcount back.
473
474Thus, it is not needed to keep any references to StreamCallback on our
475side (after we have sent an instance to the client), because we are
476the server-side. The callback object will be kept alive as long as the HAL server
477holds a strong ref to IStreamCallback proxy.
478*/
479
480class OutputStreamCallbackAidl : public StreamCallbackBase,
481 public StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>,
482 public ::aidl::android::hardware::audio::core::BnStreamCallback {
483 public:
484 explicit OutputStreamCallbackAidl(const sp<CallbackBroker>& broker)
485 : StreamCallbackBase(broker),
486 StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>(
487 *static_cast<StreamCallbackBase*>(this)) {}
488 ndk::ScopedAStatus onTransferReady() override {
489 return runCb([](CbRef cb) { cb->onWriteReady(); });
490 }
491 ndk::ScopedAStatus onError() override {
492 return runCb([](CbRef cb) { cb->onError(); });
493 }
494 ndk::ScopedAStatus onDrainReady() override {
495 return runCb([](CbRef cb) { cb->onDrainReady(); });
496 }
497};
498
499class OutputStreamEventCallbackAidl :
500 public StreamCallbackBase,
501 public StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>,
502 public StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>,
503 public ::aidl::android::hardware::audio::core::BnStreamOutEventCallback {
504 public:
505 explicit OutputStreamEventCallbackAidl(const sp<CallbackBroker>& broker)
506 : StreamCallbackBase(broker),
507 StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>(
508 *static_cast<StreamCallbackBase*>(this)),
509 StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>(
510 *static_cast<StreamCallbackBase*>(this)) {}
511 ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& in_audioMetadata) override {
512 std::basic_string<uint8_t> halMetadata(in_audioMetadata.begin(), in_audioMetadata.end());
513 return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb(
514 [&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); });
515 }
516 ndk::ScopedAStatus onRecommendedLatencyModeChanged(
517 const std::vector<AudioLatencyMode>& in_modes) override {
518 auto halModes = VALUE_OR_FATAL(
519 ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
520 in_modes,
521 ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
522 return StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::runCb(
523 [&halModes](auto cb) { cb->onRecommendedLatencyModeChanged(halModes); });
524 }
525};
526
527} // namespace
528
Mikhail Naganov31d46652023-01-10 18:29:25 +0000529status_t DeviceHalAidl::openOutputStream(
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800530 audio_io_handle_t handle, audio_devices_t devices,
531 audio_output_flags_t flags, struct audio_config* config,
532 const char* address,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000533 sp<StreamOutHalInterface>* outStream) {
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800534 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000535 if (!outStream || !config) {
536 return BAD_VALUE;
537 }
538 TIME_CHECK();
539 if (!mModule) return NO_INIT;
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800540 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
541 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
542 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
543 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, false /*isInput*/));
544 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
545 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
546 int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
547 ::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
548 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
549 AudioPortConfig mixPortConfig;
550 Cleanups cleanups;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700551 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800552 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
553 AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700554 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800555 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
556 args.portConfigId = mixPortConfig.id;
Mikhail Naganovb0c55252023-02-08 16:59:41 -0800557 const bool isOffload = isBitPositionFlagSet(
558 aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD);
559 std::shared_ptr<OutputStreamCallbackAidl> streamCb;
560 if (isOffload) {
561 streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
562 }
563 auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
564 if (isOffload) {
565 args.offloadInfo = aidlConfig.offloadInfo;
566 args.callback = streamCb;
567 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800568 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovb0c55252023-02-08 16:59:41 -0800569 args.eventCallback = eventCb;
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800570 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
571 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800572 StreamContextAidl context(ret.desc, isOffload);
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800573 if (!context.isValid()) {
574 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
575 __func__, ret.desc.toString().c_str());
576 return NO_INIT;
577 }
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700578 *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganove1253972023-05-25 17:36:48 -0700579 std::move(ret.stream), mVendorExt, this /*callbackBroker*/);
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700580 mStreams.insert(std::pair(*outStream, aidlPatch.id));
Mikhail Naganovb0c55252023-02-08 16:59:41 -0800581 void* cbCookie = (*outStream).get();
582 {
583 std::lock_guard l(mLock);
584 mCallbacks.emplace(cbCookie, Callbacks{});
585 }
586 if (streamCb) streamCb->setCookie(cbCookie);
587 eventCb->setCookie(cbCookie);
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800588 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000589 return OK;
590}
591
Mikhail Naganov31d46652023-01-10 18:29:25 +0000592status_t DeviceHalAidl::openInputStream(
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800593 audio_io_handle_t handle, audio_devices_t devices,
594 struct audio_config* config, audio_input_flags_t flags,
595 const char* address, audio_source_t source,
596 audio_devices_t outputDevice, const char* outputDeviceAddress,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000597 sp<StreamInHalInterface>* inStream) {
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800598 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000599 if (!inStream || !config) {
600 return BAD_VALUE;
601 }
602 TIME_CHECK();
603 if (!mModule) return NO_INIT;
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800604 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
605 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
606 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
607 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
608 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
609 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
610 int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
611 ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
612 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
613 AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
614 ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
615 AudioPortConfig mixPortConfig;
616 Cleanups cleanups;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700617 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800618 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700619 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800620 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
621 args.portConfigId = mixPortConfig.id;
622 RecordTrackMetadata aidlTrackMetadata{
623 .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
624 if (outputDevice != AUDIO_DEVICE_NONE) {
625 aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
626 ::aidl::android::legacy2aidl_audio_device_AudioDevice(
627 outputDevice, outputDeviceAddress));
628 }
629 args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
630 args.bufferSizeFrames = aidlConfig.frameCount;
631 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
632 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800633 StreamContextAidl context(ret.desc, false /*isAsynchronous*/);
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800634 if (!context.isValid()) {
635 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
636 __func__, ret.desc.toString().c_str());
637 return NO_INIT;
638 }
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700639 *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganove1253972023-05-25 17:36:48 -0700640 std::move(ret.stream), mVendorExt, this /*micInfoProvider*/);
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700641 mStreams.insert(std::pair(*inStream, aidlPatch.id));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800642 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000643 return OK;
644}
645
646status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
647 *supportsPatches = true;
648 return OK;
649}
650
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800651status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
652 const struct audio_port_config* sources,
653 unsigned int num_sinks,
654 const struct audio_port_config* sinks,
655 audio_patch_handle_t* patch) {
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800656 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000657 TIME_CHECK();
658 if (!mModule) return NO_INIT;
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800659 if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
660 sources == nullptr || sinks == nullptr || patch == nullptr) {
661 return BAD_VALUE;
662 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800663 // When the patch handle (*patch) is AUDIO_PATCH_HANDLE_NONE, it means
664 // the framework wants to create a new patch. The handle has to be generated
665 // by the HAL. Since handles generated this way can only be unique within
666 // a HAL module, the framework generates a globally unique handle, and maps
667 // it on the <HAL module, patch handle> pair.
668 // When the patch handle is set, it meant the framework intends to update
669 // an existing patch.
670 //
671 // This behavior corresponds to HAL module behavior, with the only difference
672 // that the HAL module uses `int32_t` for patch IDs. The following assert ensures
673 // that both the framework and the HAL use the same value for "no ID":
674 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
675 int32_t halPatchId = static_cast<int32_t>(*patch);
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800676
677 // Upon conversion, mix port configs contain audio configuration, while
678 // device port configs contain device address. This data is used to find
679 // or create HAL configs.
680 std::vector<AudioPortConfig> aidlSources, aidlSinks;
681 for (unsigned int i = 0; i < num_sources; ++i) {
682 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
683 sources[i].role, sources[i].type)) ==
684 ::aidl::android::AudioPortDirection::INPUT;
685 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
686 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
687 sources[i], isInput, 0)));
688 }
689 for (unsigned int i = 0; i < num_sinks; ++i) {
690 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
691 sinks[i].role, sinks[i].type)) ==
692 ::aidl::android::AudioPortDirection::INPUT;
693 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
694 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
695 sinks[i], isInput, 0)));
696 }
697 Cleanups cleanups;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800698 auto existingPatchIt = halPatchId != 0 ? mPatches.find(halPatchId): mPatches.end();
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800699 AudioPatch aidlPatch;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800700 if (existingPatchIt != mPatches.end()) {
701 aidlPatch = existingPatchIt->second;
702 aidlPatch.sourcePortConfigIds.clear();
703 aidlPatch.sinkPortConfigIds.clear();
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800704 }
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800705 ALOGD("%s: sources: %s, sinks: %s",
706 __func__, ::android::internal::ToString(aidlSources).c_str(),
707 ::android::internal::ToString(aidlSinks).c_str());
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800708 auto fillPortConfigs = [&](
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700709 const std::vector<AudioPortConfig>& configs,
710 const std::set<int32_t>& destinationPortIds,
711 std::vector<int32_t>* ids, std::set<int32_t>* portIds) -> status_t {
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800712 for (const auto& s : configs) {
713 AudioPortConfig portConfig;
714 bool created = false;
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700715 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
716 s, destinationPortIds, &portConfig, &created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800717 if (created) {
718 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, portConfig.id);
719 }
720 ids->push_back(portConfig.id);
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700721 if (portIds != nullptr) {
722 portIds->insert(portConfig.portId);
723 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800724 }
725 return OK;
726 };
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700727 // When looking up port configs, the destinationPortId is only used for mix ports.
728 // Thus, we process device port configs first, and look up the destination port ID from them.
729 bool sourceIsDevice = std::any_of(aidlSources.begin(), aidlSources.end(),
730 [](const auto& config) { return config.ext.getTag() == AudioPortExt::device; });
731 const std::vector<AudioPortConfig>& devicePortConfigs =
732 sourceIsDevice ? aidlSources : aidlSinks;
733 std::vector<int32_t>* devicePortConfigIds =
734 sourceIsDevice ? &aidlPatch.sourcePortConfigIds : &aidlPatch.sinkPortConfigIds;
735 const std::vector<AudioPortConfig>& mixPortConfigs =
736 sourceIsDevice ? aidlSinks : aidlSources;
737 std::vector<int32_t>* mixPortConfigIds =
738 sourceIsDevice ? &aidlPatch.sinkPortConfigIds : &aidlPatch.sourcePortConfigIds;
739 std::set<int32_t> devicePortIds;
740 RETURN_STATUS_IF_ERROR(fillPortConfigs(
741 devicePortConfigs, std::set<int32_t>(), devicePortConfigIds, &devicePortIds));
742 RETURN_STATUS_IF_ERROR(fillPortConfigs(
743 mixPortConfigs, devicePortIds, mixPortConfigIds, nullptr));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800744 if (existingPatchIt != mPatches.end()) {
745 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
746 mModule->setAudioPatch(aidlPatch, &aidlPatch)));
747 existingPatchIt->second = aidlPatch;
748 } else {
749 bool created = false;
750 RETURN_STATUS_IF_ERROR(findOrCreatePatch(aidlPatch, &aidlPatch, &created));
751 // Since no cleanup of the patch is needed, 'created' is ignored.
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800752 halPatchId = aidlPatch.id;
753 *patch = static_cast<audio_patch_handle_t>(halPatchId);
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800754 }
755 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000756 return OK;
757}
758
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800759status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800760 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000761 TIME_CHECK();
762 if (!mModule) return NO_INIT;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800763 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
764 if (patch == AUDIO_PATCH_HANDLE_NONE) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800765 return BAD_VALUE;
766 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800767 int32_t halPatchId = static_cast<int32_t>(patch);
768 auto patchIt = mPatches.find(halPatchId);
769 if (patchIt == mPatches.end()) {
770 ALOGE("%s: patch with id %d not found", __func__, halPatchId);
771 return BAD_VALUE;
772 }
773 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->resetAudioPatch(halPatchId)));
774 mPatches.erase(patchIt);
Shunkai Yao51202502022-12-12 06:11:46 +0000775 return OK;
776}
777
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700778status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
779 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000780 TIME_CHECK();
781 if (!mModule) return NO_INIT;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700782 if (port == nullptr) {
783 return BAD_VALUE;
784 }
785 audio_port_v7 portV7;
786 audio_populate_audio_port_v7(port, &portV7);
787 RETURN_STATUS_IF_ERROR(getAudioPort(&portV7));
788 return audio_populate_audio_port(&portV7, port) ? OK : BAD_VALUE;
789}
790
791status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
792 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
793 TIME_CHECK();
794 if (!mModule) return NO_INIT;
795 if (port == nullptr) {
796 return BAD_VALUE;
797 }
798 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
799 ::aidl::android::AudioPortDirection::INPUT;
800 auto aidlPort = VALUE_OR_RETURN_STATUS(
801 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
802 if (aidlPort.ext.getTag() != AudioPortExt::device) {
803 ALOGE("%s: provided port is not a device port (module %s): %s",
804 __func__, mInstance.c_str(), aidlPort.toString().c_str());
805 return BAD_VALUE;
806 }
807 const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
808 // It seems that we don't have to call HAL since all valid ports have been added either
809 // during initialization, or while handling connection of an external device.
810 auto portsIt = findPort(matchDevice);
811 if (portsIt == mPorts.end()) {
812 ALOGE("%s: device port for device %s is not found in the module %s",
813 __func__, matchDevice.toString().c_str(), mInstance.c_str());
814 return BAD_VALUE;
815 }
816 const int32_t fwkId = aidlPort.id;
817 aidlPort = portsIt->second;
818 aidlPort.id = fwkId;
819 *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
820 aidlPort, isInput));
821 return OK;
822}
823
824status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
825 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
826 TIME_CHECK();
827 if (!mModule) return NO_INIT;
828 if (config == nullptr) {
829 return BAD_VALUE;
830 }
831 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
832 config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
833 AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
834 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
835 *config, isInput, 0 /*portId*/));
836 AudioPortConfig portConfig;
837 bool created = false;
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700838 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
839 requestedPortConfig, std::set<int32_t>(), &portConfig, &created));
Shunkai Yao51202502022-12-12 06:11:46 +0000840 return OK;
841}
842
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800843MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
844 if (mMicrophones.status == Microphones::Status::UNKNOWN) {
845 TIME_CHECK();
846 std::vector<MicrophoneInfo> aidlInfo;
847 status_t status = statusTFromBinderStatus(mModule->getMicrophones(&aidlInfo));
848 if (status == OK) {
849 mMicrophones.status = Microphones::Status::QUERIED;
850 mMicrophones.info = std::move(aidlInfo);
851 } else if (status == INVALID_OPERATION) {
852 mMicrophones.status = Microphones::Status::NOT_SUPPORTED;
853 } else {
854 ALOGE("%s: Unexpected status from 'IModule.getMicrophones': %d", __func__, status);
855 return {};
856 }
857 }
858 if (mMicrophones.status == Microphones::Status::QUERIED) {
859 return &mMicrophones.info;
860 }
861 return {}; // NOT_SUPPORTED
862}
863
Shunkai Yao51202502022-12-12 06:11:46 +0000864status_t DeviceHalAidl::getMicrophones(
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800865 std::vector<audio_microphone_characteristic_t>* microphones) {
866 if (!microphones) {
867 return BAD_VALUE;
868 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000869 TIME_CHECK();
870 if (!mModule) return NO_INIT;
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800871 auto staticInfo = getMicrophoneInfo();
872 if (!staticInfo) return INVALID_OPERATION;
873 std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
874 emptyDynamicInfo.reserve(staticInfo->size());
875 std::transform(staticInfo->begin(), staticInfo->end(), std::back_inserter(emptyDynamicInfo),
876 [](const auto& info) { return MicrophoneDynamicInfo{ .id = info.id }; });
877 *microphones = VALUE_OR_RETURN_STATUS(
878 ::aidl::android::convertContainers<std::vector<audio_microphone_characteristic_t>>(
879 *staticInfo, emptyDynamicInfo,
880 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t)
881 );
Shunkai Yao51202502022-12-12 06:11:46 +0000882 return OK;
883}
884
Mikhail Naganov570ce382023-06-14 18:00:13 -0700885status_t DeviceHalAidl::addDeviceEffect(const struct audio_port_config *device __unused,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000886 sp<EffectHalInterface> effect) {
Shunkai Yao51202502022-12-12 06:11:46 +0000887 if (!effect) {
888 return BAD_VALUE;
889 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000890 TIME_CHECK();
891 if (!mModule) return NO_INIT;
892 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000893 return OK;
894}
Mikhail Naganov570ce382023-06-14 18:00:13 -0700895status_t DeviceHalAidl::removeDeviceEffect(const struct audio_port_config *device __unused,
Shunkai Yao51202502022-12-12 06:11:46 +0000896 sp<EffectHalInterface> effect) {
897 if (!effect) {
898 return BAD_VALUE;
899 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000900 TIME_CHECK();
901 if (!mModule) return NO_INIT;
902 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000903 return OK;
904}
905
906status_t DeviceHalAidl::getMmapPolicyInfos(
David Li9cf5e622023-03-21 00:51:10 +0800907 media::audio::common::AudioMMapPolicyType policyType,
908 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000909 TIME_CHECK();
Mikhail Naganovbfbb75b2023-04-21 18:48:16 -0700910 AudioMMapPolicyType mmapPolicyType = VALUE_OR_RETURN_STATUS(
911 cpp2ndk_AudioMMapPolicyType(policyType));
David Li9cf5e622023-03-21 00:51:10 +0800912
913 std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
914
915 if (status_t status = statusTFromBinderStatus(
916 mModule->getMmapPolicyInfos(mmapPolicyType, &mmapPolicyInfos)); status != OK) {
917 return status;
918 }
919
920 *policyInfos = VALUE_OR_RETURN_STATUS(
921 convertContainer<std::vector<media::audio::common::AudioMMapPolicyInfo>>(
922 mmapPolicyInfos, ndk2cpp_AudioMMapPolicyInfo));
Shunkai Yao51202502022-12-12 06:11:46 +0000923 return OK;
924}
925
926int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000927 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800928 int32_t mixerBurstCount = 0;
929 if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
930 return mixerBurstCount;
931 }
932 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000933}
934
935int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000936 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800937 int32_t hardwareBurstMinUsec = 0;
938 if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
939 return hardwareBurstMinUsec;
940 }
941 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000942}
943
944error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000945 TIME_CHECK();
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700946 if (!mModule) return NO_INIT;
947 int32_t aidlHwAvSync;
948 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
949 return VALUE_OR_RETURN_STATUS(
950 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +0000951}
952
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000953status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
954 TIME_CHECK();
955 if (!mModule) return NO_INIT;
956 return mModule->dump(fd, Args(args).args(), args.size());
David Li9cf5e622023-03-21 00:51:10 +0800957}
Shunkai Yao51202502022-12-12 06:11:46 +0000958
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700959int32_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000960 TIME_CHECK();
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700961 if (!mModule) return NO_INIT;
962 if (supports == nullptr) {
963 return BAD_VALUE;
964 }
965 return statusTFromBinderStatus(mModule->supportsVariableLatency(supports));
Shunkai Yao51202502022-12-12 06:11:46 +0000966}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000967
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100968status_t DeviceHalAidl::getSoundDoseInterface(const std::string& module,
969 ::ndk::SpAIBinder* soundDoseBinder) {
970 TIME_CHECK();
971 if (!mModule) return NO_INIT;
972 if (mSoundDose == nullptr) {
973 ndk::ScopedAStatus status = mModule->getSoundDose(&mSoundDose);
974 if (!status.isOk()) {
975 ALOGE("%s failed to return the sound dose interface for module %s: %s",
976 __func__,
977 module.c_str(),
978 status.getDescription().c_str());
979 return BAD_VALUE;
980 }
981 }
982 *soundDoseBinder = mSoundDose->asBinder();
983 ALOGI("%s using audio AIDL HAL sound dose interface", __func__);
984
985 return OK;
986}
987
jiabinc0048632023-04-27 22:04:31 +0000988status_t DeviceHalAidl::prepareToDisconnectExternalDevice(const struct audio_port_v7* port) {
989 // There is not AIDL API defined for `prepareToDisconnectExternalDevice`.
990 // Call `setConnectedState` instead.
991 // TODO(b/279824103): call prepareToDisconnectExternalDevice when it is added.
992 const status_t status = setConnectedState(port, false /*connected*/);
993 if (status == NO_ERROR) {
994 mDeviceDisconnectionNotified.insert(port->id);
995 }
996 return status;
997}
998
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700999status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
1000 TIME_CHECK();
1001 if (!mModule) return NO_INIT;
1002 if (port == nullptr) {
1003 return BAD_VALUE;
1004 }
jiabinc0048632023-04-27 22:04:31 +00001005 if (!connected && mDeviceDisconnectionNotified.erase(port->id) > 0) {
1006 // For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
1007 // and then call `setConnectedState`. However, there is no API for
1008 // `prepareToDisconnectExternalDevice` yet. In that case, `setConnectedState` will be
1009 // called when calling `prepareToDisconnectExternalDevice`. Do not call to the HAL if
1010 // previous call is successful. Also remove the cache here to avoid a large cache after
1011 // a long run.
1012 return NO_ERROR;
1013 }
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001014 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
1015 ::aidl::android::AudioPortDirection::INPUT;
1016 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
1017 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
1018 if (aidlPort.ext.getTag() != AudioPortExt::device) {
1019 ALOGE("%s: provided port is not a device port (module %s): %s",
1020 __func__, mInstance.c_str(), aidlPort.toString().c_str());
1021 return BAD_VALUE;
1022 }
1023 if (connected) {
1024 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1025 // Reset the device address to find the "template" port.
1026 matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
1027 auto portsIt = findPort(matchDevice);
1028 if (portsIt == mPorts.end()) {
1029 ALOGW("%s: device port for device %s is not found in the module %s",
1030 __func__, matchDevice.toString().c_str(), mInstance.c_str());
1031 return BAD_VALUE;
1032 }
1033 // Use the ID of the "template" port, use all the information from the provided port.
1034 aidlPort.id = portsIt->first;
1035 AudioPort connectedPort;
1036 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
1037 aidlPort, &connectedPort)));
1038 const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
1039 LOG_ALWAYS_FATAL_IF(!inserted,
1040 "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
1041 __func__, mInstance.c_str(), connectedPort.toString().c_str(),
1042 it->second.toString().c_str());
1043 } else { // !connected
1044 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1045 auto portsIt = findPort(matchDevice);
1046 if (portsIt == mPorts.end()) {
1047 ALOGW("%s: device port for device %s is not found in the module %s",
1048 __func__, matchDevice.toString().c_str(), mInstance.c_str());
1049 return BAD_VALUE;
1050 }
1051 // Any streams opened on the external device must be closed by this time,
1052 // thus we can clean up patches and port configs that were created for them.
1053 resetUnusedPatchesAndPortConfigs();
1054 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
1055 portsIt->second.id)));
1056 mPorts.erase(portsIt);
1057 }
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001058 return updateRoutes();
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001059}
1060
1061status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
1062 TIME_CHECK();
1063 if (!mModule) return NO_INIT;
1064 ModuleDebug debug{ .simulateDeviceConnections = enabled };
1065 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
1066 // This is important to log as it affects HAL behavior.
1067 if (status == OK) {
1068 ALOGI("%s: set enabled: %d", __func__, enabled);
1069 } else {
1070 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
1071 }
1072 return status;
1073}
1074
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001075bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
1076 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1077 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1078}
1079
1080bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
1081 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1082 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1083 return p.portId == mDefaultInputPortId;
1084 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1085 return p.portId == mDefaultOutputPortId;
1086 }
1087 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1088}
1089
David Lia8f1e582023-03-30 21:08:06 +08001090status_t DeviceHalAidl::createOrUpdatePortConfig(
1091 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool* created) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001092 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001093 AudioPortConfig appliedPortConfig;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001094 bool applied = false;
1095 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001096 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001097 if (!applied) {
1098 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001099 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001100 if (!applied) {
1101 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001102 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001103 return NO_INIT;
1104 }
1105 }
David Lia8f1e582023-03-30 21:08:06 +08001106
1107 int32_t id = appliedPortConfig.id;
1108 if (requestedPortConfig.id != 0 && requestedPortConfig.id != id) {
1109 LOG_ALWAYS_FATAL("%s: requested port config id %d changed to %d", __func__,
1110 requestedPortConfig.id, id);
1111 }
1112
1113 auto [it, inserted] = mPortConfigs.insert_or_assign(std::move(id),
1114 std::move(appliedPortConfig));
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001115 *result = it;
David Lia8f1e582023-03-30 21:08:06 +08001116 *created = inserted;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001117 return OK;
1118}
1119
Mikhail Naganove1253972023-05-25 17:36:48 -07001120status_t DeviceHalAidl::filterAndRetrieveBtA2dpParameters(
1121 AudioParameter &keys, AudioParameter *result) {
1122 TIME_CHECK();
1123 if (String8 key = String8(AudioParameter::keyReconfigA2dpSupported); keys.containsKey(key)) {
1124 keys.remove(key);
1125 bool supports;
1126 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1127 mBluetoothA2dp->supportsOffloadReconfiguration(&supports)));
1128 result->addInt(key, supports ? 1 : 0);
1129 }
1130 return OK;
1131}
1132
Mikhail Naganov27382bb2023-04-27 18:14:15 -07001133status_t DeviceHalAidl::filterAndUpdateBtA2dpParameters(AudioParameter &parameters) {
1134 TIME_CHECK();
1135 std::optional<bool> a2dpEnabled;
Mikhail Naganove1253972023-05-25 17:36:48 -07001136 std::optional<std::vector<VendorParameter>> reconfigureOffload;
Mikhail Naganov27382bb2023-04-27 18:14:15 -07001137 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1138 parameters, String8(AudioParameter::keyBtA2dpSuspended),
1139 [&a2dpEnabled](const String8& trueOrFalse) {
1140 if (trueOrFalse == AudioParameter::valueTrue) {
1141 a2dpEnabled = false; // 'suspended' == true
1142 return OK;
1143 } else if (trueOrFalse == AudioParameter::valueFalse) {
1144 a2dpEnabled = true; // 'suspended' == false
1145 return OK;
1146 }
1147 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1148 AudioParameter::keyBtA2dpSuspended, trueOrFalse.c_str());
1149 return BAD_VALUE;
1150 }));
Mikhail Naganove1253972023-05-25 17:36:48 -07001151 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1152 parameters, String8(AudioParameter::keyReconfigA2dp),
1153 [&](const String8& value) -> status_t {
1154 if (mVendorExt != nullptr) {
1155 std::vector<VendorParameter> result;
1156 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1157 mVendorExt->parseBluetoothA2dpReconfigureOffload(
1158 std::string(value.c_str()), &result)));
1159 reconfigureOffload = std::move(result);
1160 } else {
1161 reconfigureOffload = std::vector<VendorParameter>();
1162 }
1163 return OK;
1164 }));
Mikhail Naganov27382bb2023-04-27 18:14:15 -07001165 if (mBluetoothA2dp != nullptr && a2dpEnabled.has_value()) {
1166 return statusTFromBinderStatus(mBluetoothA2dp->setEnabled(a2dpEnabled.value()));
1167 }
Mikhail Naganove1253972023-05-25 17:36:48 -07001168 if (mBluetoothA2dp != nullptr && reconfigureOffload.has_value()) {
1169 return statusTFromBinderStatus(mBluetoothA2dp->reconfigureOffload(
1170 reconfigureOffload.value()));
1171 }
Mikhail Naganov27382bb2023-04-27 18:14:15 -07001172 return OK;
1173}
1174
1175status_t DeviceHalAidl::filterAndUpdateBtHfpParameters(AudioParameter &parameters) {
1176 TIME_CHECK();
1177 IBluetooth::HfpConfig hfpConfig;
1178 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1179 parameters, String8(AudioParameter::keyBtHfpEnable),
1180 [&hfpConfig](const String8& trueOrFalse) {
1181 if (trueOrFalse == AudioParameter::valueTrue) {
1182 hfpConfig.isEnabled = Boolean{ .value = true };
1183 return OK;
1184 } else if (trueOrFalse == AudioParameter::valueFalse) {
1185 hfpConfig.isEnabled = Boolean{ .value = false };
1186 return OK;
1187 }
1188 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1189 AudioParameter::keyBtHfpEnable, trueOrFalse.c_str());
1190 return BAD_VALUE;
1191 }));
1192 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1193 parameters, String8(AudioParameter::keyBtHfpSamplingRate),
1194 [&hfpConfig](int sampleRate) {
1195 return sampleRate > 0 ?
1196 hfpConfig.sampleRate = Int{ .value = sampleRate }, OK : BAD_VALUE;
1197 }));
1198 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1199 parameters, String8(AudioParameter::keyBtHfpVolume),
1200 [&hfpConfig](int volume0to15) {
1201 if (volume0to15 >= 0 && volume0to15 <= 15) {
1202 hfpConfig.volume = Float{ .value = volume0to15 / 15.0f };
1203 return OK;
1204 }
1205 return BAD_VALUE;
1206 }));
1207 if (mBluetooth != nullptr && hfpConfig != IBluetooth::HfpConfig{}) {
1208 IBluetooth::HfpConfig newHfpConfig;
1209 return statusTFromBinderStatus(mBluetooth->setHfpConfig(hfpConfig, &newHfpConfig));
1210 }
1211 return OK;
1212}
1213
1214status_t DeviceHalAidl::filterAndUpdateBtLeParameters(AudioParameter &parameters) {
1215 TIME_CHECK();
1216 std::optional<bool> leEnabled;
1217 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1218 parameters, String8(AudioParameter::keyBtLeSuspended),
1219 [&leEnabled](const String8& trueOrFalse) {
1220 if (trueOrFalse == AudioParameter::valueTrue) {
1221 leEnabled = false; // 'suspended' == true
1222 return OK;
1223 } else if (trueOrFalse == AudioParameter::valueFalse) {
1224 leEnabled = true; // 'suspended' == false
1225 return OK;
1226 }
1227 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1228 AudioParameter::keyBtLeSuspended, trueOrFalse.c_str());
1229 return BAD_VALUE;
1230 }));
1231 if (mBluetoothLe != nullptr && leEnabled.has_value()) {
1232 return statusTFromBinderStatus(mBluetoothLe->setEnabled(leEnabled.value()));
1233 }
1234 return OK;
1235}
1236
1237status_t DeviceHalAidl::filterAndUpdateBtScoParameters(AudioParameter &parameters) {
1238 TIME_CHECK();
1239 IBluetooth::ScoConfig scoConfig;
1240 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1241 parameters, String8(AudioParameter::keyBtSco),
1242 [&scoConfig](const String8& onOrOff) {
1243 if (onOrOff == AudioParameter::valueOn) {
1244 scoConfig.isEnabled = Boolean{ .value = true };
1245 return OK;
1246 } else if (onOrOff == AudioParameter::valueOff) {
1247 scoConfig.isEnabled = Boolean{ .value = false };
1248 return OK;
1249 }
1250 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1251 AudioParameter::keyBtSco, onOrOff.c_str());
1252 return BAD_VALUE;
1253 }));
1254 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1255 parameters, String8(AudioParameter::keyBtScoHeadsetName),
1256 [&scoConfig](const String8& name) {
1257 scoConfig.debugName = name;
1258 return OK;
1259 }));
1260 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1261 parameters, String8(AudioParameter::keyBtNrec),
1262 [&scoConfig](const String8& onOrOff) {
1263 if (onOrOff == AudioParameter::valueOn) {
1264 scoConfig.isNrecEnabled = Boolean{ .value = true };
1265 return OK;
1266 } else if (onOrOff == AudioParameter::valueOff) {
1267 scoConfig.isNrecEnabled = Boolean{ .value = false };
1268 return OK;
1269 }
1270 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1271 AudioParameter::keyBtNrec, onOrOff.c_str());
1272 return BAD_VALUE;
1273 }));
1274 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1275 parameters, String8(AudioParameter::keyBtScoWb),
1276 [&scoConfig](const String8& onOrOff) {
1277 if (onOrOff == AudioParameter::valueOn) {
1278 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO_WB;
1279 return OK;
1280 } else if (onOrOff == AudioParameter::valueOff) {
1281 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO;
1282 return OK;
1283 }
1284 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1285 AudioParameter::keyBtScoWb, onOrOff.c_str());
1286 return BAD_VALUE;
1287 }));
1288 if (mBluetooth != nullptr && scoConfig != IBluetooth::ScoConfig{}) {
1289 IBluetooth::ScoConfig newScoConfig;
1290 return statusTFromBinderStatus(mBluetooth->setScoConfig(scoConfig, &newScoConfig));
1291 }
1292 return OK;
1293}
1294
Mikhail Naganovbaab5012023-05-31 14:24:48 -07001295status_t DeviceHalAidl::filterAndUpdateScreenParameters(AudioParameter &parameters) {
1296 TIME_CHECK();
1297 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1298 parameters, String8(AudioParameter::keyScreenState),
1299 [&](const String8& onOrOff) -> status_t {
1300 std::optional<bool> isTurnedOn;
1301 if (onOrOff == AudioParameter::valueOn) {
1302 isTurnedOn = true;
1303 } else if (onOrOff == AudioParameter::valueOff) {
1304 isTurnedOn = false;
1305 }
1306 if (!isTurnedOn.has_value()) {
1307 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1308 AudioParameter::keyScreenState, onOrOff.c_str());
1309 return BAD_VALUE;
1310 }
1311 return statusTFromBinderStatus(
1312 mModule->updateScreenState(isTurnedOn.value()));
1313 }));
1314 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1315 parameters, String8(AudioParameter::keyScreenRotation),
1316 [&](int rotationDegrees) -> status_t {
1317 IModule::ScreenRotation rotation;
1318 switch (rotationDegrees) {
1319 case 0: rotation = IModule::ScreenRotation::DEG_0; break;
1320 case 90: rotation = IModule::ScreenRotation::DEG_90; break;
1321 case 180: rotation = IModule::ScreenRotation::DEG_180; break;
1322 case 270: rotation = IModule::ScreenRotation::DEG_270; break;
1323 default:
1324 ALOGE("setParameters: parameter key \"%s\" has invalid value %d",
1325 AudioParameter::keyScreenRotation, rotationDegrees);
1326 return BAD_VALUE;
1327 }
1328 return statusTFromBinderStatus(mModule->updateScreenRotation(rotation));
1329 }));
1330 return OK;
1331}
1332
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001333status_t DeviceHalAidl::findOrCreatePatch(
1334 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
1335 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
1336 requestedPatch.sourcePortConfigIds.end());
1337 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
1338 requestedPatch.sinkPortConfigIds.end());
1339 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
1340}
1341
1342status_t DeviceHalAidl::findOrCreatePatch(
1343 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
1344 AudioPatch* patch, bool* created) {
1345 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
1346 if (patchIt == mPatches.end()) {
1347 TIME_CHECK();
1348 AudioPatch requestedPatch, appliedPatch;
1349 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
1350 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
1351 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
1352 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
1353 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
1354 requestedPatch, &appliedPatch)));
1355 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
1356 *created = true;
1357 } else {
1358 *created = false;
1359 }
1360 *patch = patchIt->second;
1361 return OK;
1362}
1363
jiabin2248fa12023-04-27 22:04:16 +00001364status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device, const AudioConfig* config,
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001365 AudioPortConfig* portConfig, bool* created) {
1366 auto portConfigIt = findPortConfig(device);
1367 if (portConfigIt == mPortConfigs.end()) {
1368 auto portsIt = findPort(device);
1369 if (portsIt == mPorts.end()) {
1370 ALOGE("%s: device port for device %s is not found in the module %s",
1371 __func__, device.toString().c_str(), mInstance.c_str());
1372 return BAD_VALUE;
1373 }
1374 AudioPortConfig requestedPortConfig;
1375 requestedPortConfig.portId = portsIt->first;
jiabin2248fa12023-04-27 22:04:16 +00001376 if (config != nullptr) {
1377 setPortConfigFromConfig(&requestedPortConfig, *config);
1378 }
David Lia8f1e582023-03-30 21:08:06 +08001379 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1380 created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001381 } else {
1382 *created = false;
1383 }
1384 *portConfig = portConfigIt->second;
1385 return OK;
1386}
1387
1388status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001389 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001390 AudioSource source, const std::set<int32_t>& destinationPortIds,
1391 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001392 // These flags get removed one by one in this order when retrying port finding.
1393 static const std::vector<AudioInputFlags> kOptionalInputFlags{
1394 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001395 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001396 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001397 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
1398 AudioIoFlags matchFlags = flags.value();
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001399 auto portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001400 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
1401 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
1402 if (!isBitPositionFlagSet(
1403 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
1404 ++optionalInputFlagsIt;
1405 continue;
1406 }
1407 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
1408 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001409 portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001410 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
1411 "retried with flags %s", __func__, config.toString().c_str(),
1412 flags.value().toString().c_str(), mInstance.c_str(),
1413 matchFlags.toString().c_str());
1414 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001415 if (portsIt == mPorts.end()) {
1416 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001417 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001418 mInstance.c_str());
1419 return BAD_VALUE;
1420 }
1421 AudioPortConfig requestedPortConfig;
1422 requestedPortConfig.portId = portsIt->first;
1423 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001424 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001425 if (matchFlags.getTag() == AudioIoFlags::Tag::input
1426 && source != AudioSource::SYS_RESERVED_INVALID) {
1427 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
1428 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
1429 }
David Lia8f1e582023-03-30 21:08:06 +08001430 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1431 created));
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001432 } else if (!flags.has_value()) {
1433 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
1434 "and was not created as flags are not specified",
1435 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
1436 return BAD_VALUE;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001437 } else {
David Lia8f1e582023-03-30 21:08:06 +08001438 AudioPortConfig requestedPortConfig = portConfigIt->second;
1439 if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
1440 AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
1441 if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
1442 source != AudioSource::SYS_RESERVED_INVALID) {
1443 mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
1444 }
1445 }
1446
1447 if (requestedPortConfig != portConfigIt->second) {
1448 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1449 created));
1450 } else {
1451 *created = false;
1452 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001453 }
1454 *portConfig = portConfigIt->second;
1455 return OK;
1456}
1457
1458status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001459 const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
1460 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001461 using Tag = AudioPortExt::Tag;
1462 if (requestedPortConfig.ext.getTag() == Tag::mix) {
1463 if (const auto& p = requestedPortConfig;
1464 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001465 !p.format.has_value()) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001466 ALOGW("%s: provided mix port config is not fully specified: %s",
1467 __func__, p.toString().c_str());
1468 return BAD_VALUE;
1469 }
1470 AudioConfig config;
1471 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001472 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
1473 AudioPortMixExtUseCase::Tag::source ?
1474 requestedPortConfig.ext.get<Tag::mix>().usecase.
1475 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001476 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001477 requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
1478 portConfig, created);
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001479 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
1480 return findOrCreatePortConfig(
jiabin2248fa12023-04-27 22:04:16 +00001481 requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
1482 portConfig, created);
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001483 }
1484 ALOGW("%s: unsupported audio port config: %s",
1485 __func__, requestedPortConfig.toString().c_str());
1486 return BAD_VALUE;
1487}
1488
1489DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
1490 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
1491 return std::find_if(mPatches.begin(), mPatches.end(),
1492 [&](const auto& pair) {
1493 const auto& p = pair.second;
1494 std::set<int32_t> patchSrcs(
1495 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
1496 std::set<int32_t> patchSinks(
1497 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
1498 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
1499}
1500
1501DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001502 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1503 return mPorts.find(mDefaultInputPortId);
1504 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1505 return mPorts.find(mDefaultOutputPortId);
1506 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001507 return std::find_if(mPorts.begin(), mPorts.end(),
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001508 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001509}
1510
1511DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001512 const AudioConfig& config, const AudioIoFlags& flags,
1513 const std::set<int32_t>& destinationPortIds) {
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001514 auto belongsToProfile = [&config](const AudioProfile& prof) {
1515 return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
1516 (config.base.channelMask.getTag() == AudioChannelLayout::none ||
1517 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
1518 config.base.channelMask) != prof.channelMasks.end()) &&
1519 (config.base.sampleRate == 0 ||
1520 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
1521 config.base.sampleRate) != prof.sampleRates.end());
1522 };
jiabin2248fa12023-04-27 22:04:16 +00001523 static const std::vector<AudioOutputFlags> kOptionalOutputFlags{AudioOutputFlags::BIT_PERFECT};
1524 int optionalFlags = 0;
1525 auto flagMatches = [&flags, &optionalFlags](const AudioIoFlags& portFlags) {
1526 // Ports should be able to match if the optional flags are not requested.
1527 return portFlags == flags ||
1528 (portFlags.getTag() == AudioIoFlags::Tag::output &&
1529 AudioIoFlags::make<AudioIoFlags::Tag::output>(
1530 portFlags.get<AudioIoFlags::Tag::output>() &
1531 ~optionalFlags) == flags);
1532 };
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001533 auto matcher = [&](const auto& pair) {
1534 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001535 return p.ext.getTag() == AudioPortExt::Tag::mix &&
jiabin2248fa12023-04-27 22:04:16 +00001536 flagMatches(p.flags) &&
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001537 (destinationPortIds.empty() ||
1538 std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
1539 [&](const int32_t destId) { return mRoutingMatrix.count(
1540 std::make_pair(p.id, destId)) != 0; })) &&
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001541 (p.profiles.empty() ||
1542 std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
1543 p.profiles.end()); };
jiabin2248fa12023-04-27 22:04:16 +00001544 auto result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1545 if (result == mPorts.end() && flags.getTag() == AudioIoFlags::Tag::output) {
1546 auto optionalOutputFlagsIt = kOptionalOutputFlags.begin();
1547 while (result == mPorts.end() && optionalOutputFlagsIt != kOptionalOutputFlags.end()) {
1548 if (isBitPositionFlagSet(
1549 flags.get<AudioIoFlags::Tag::output>(), *optionalOutputFlagsIt)) {
1550 // If the flag is set by the request, it must be matched.
1551 ++optionalOutputFlagsIt;
1552 continue;
1553 }
1554 optionalFlags |= makeBitPositionFlagMask(*optionalOutputFlagsIt++);
1555 result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1556 ALOGI("%s: port for config %s, flags %s was not found in the module %s, "
1557 "retried with excluding optional flags %#x", __func__, config.toString().c_str(),
1558 flags.toString().c_str(), mInstance.c_str(), optionalFlags);
1559 }
1560 }
1561 return result;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001562}
1563
1564DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001565 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001566 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001567}
1568
1569DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001570 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001571 using Tag = AudioPortExt::Tag;
1572 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
1573 [&](const auto& pair) {
1574 const auto& p = pair.second;
1575 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
1576 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
1577 !p.format.has_value() || !p.flags.has_value(),
1578 "%s: stored mix port config is not fully specified: %s",
1579 __func__, p.toString().c_str());
1580 return p.ext.getTag() == Tag::mix &&
1581 isConfigEqualToPortConfig(config, p) &&
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001582 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001583 p.ext.template get<Tag::mix>().handle == ioHandle; });
1584}
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001585
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001586void DeviceHalAidl::resetPatch(int32_t patchId) {
1587 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1588 mPatches.erase(it);
1589 TIME_CHECK();
1590 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1591 ALOGE("%s: error while resetting patch %d: %s",
1592 __func__, patchId, status.getDescription().c_str());
1593 }
1594 return;
1595 }
1596 ALOGE("%s: patch id %d not found", __func__, patchId);
1597}
1598
1599void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1600 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1601 mPortConfigs.erase(it);
1602 TIME_CHECK();
1603 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1604 !status.isOk()) {
1605 ALOGE("%s: error while resetting port config %d: %s",
1606 __func__, portConfigId, status.getDescription().c_str());
1607 }
1608 return;
1609 }
1610 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1611}
1612
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001613void DeviceHalAidl::resetUnusedPatches() {
1614 // Since patches can be created independently of streams via 'createAudioPatch',
1615 // here we only clean up patches for released streams.
1616 for (auto it = mStreams.begin(); it != mStreams.end(); ) {
1617 if (auto streamSp = it->first.promote(); streamSp) {
1618 ++it;
1619 } else {
1620 resetPatch(it->second);
1621 it = mStreams.erase(it);
1622 }
1623 }
1624}
1625
1626void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
1627 resetUnusedPatches();
1628 resetUnusedPortConfigs();
1629}
1630
1631void DeviceHalAidl::resetUnusedPortConfigs() {
1632 // The assumption is that port configs are used to create patches
1633 // (or to open streams, but that involves creation of patches, too). Thus,
1634 // orphaned port configs can and should be reset.
1635 std::set<int32_t> portConfigIds;
1636 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
1637 std::inserter(portConfigIds, portConfigIds.end()),
1638 [](const auto& pcPair) { return pcPair.first; });
1639 for (const auto& p : mPatches) {
1640 for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
1641 for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
1642 }
jiabin2248fa12023-04-27 22:04:16 +00001643 for (int32_t id : mInitialPortConfigIds) {
1644 portConfigIds.erase(id);
1645 }
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001646 for (int32_t id : portConfigIds) resetPortConfig(id);
1647}
1648
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001649status_t DeviceHalAidl::updateRoutes() {
1650 TIME_CHECK();
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001651 RETURN_STATUS_IF_ERROR(
Mikhail Naganov2d814892023-04-24 13:06:04 -07001652 statusTFromBinderStatus(mModule->getAudioRoutes(&mRoutes)));
1653 ALOGW_IF(mRoutes.empty(), "%s: module %s returned an empty list of audio routes",
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001654 __func__, mInstance.c_str());
1655 mRoutingMatrix.clear();
Mikhail Naganov2d814892023-04-24 13:06:04 -07001656 for (const auto& r : mRoutes) {
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001657 for (auto portId : r.sourcePortIds) {
1658 mRoutingMatrix.emplace(r.sinkPortId, portId);
1659 mRoutingMatrix.emplace(portId, r.sinkPortId);
1660 }
1661 }
1662 return OK;
1663}
1664
Mikhail Naganovb0c55252023-02-08 16:59:41 -08001665void DeviceHalAidl::clearCallbacks(void* cookie) {
1666 std::lock_guard l(mLock);
1667 mCallbacks.erase(cookie);
1668}
1669
1670sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1671 return getCallbackImpl(cookie, &Callbacks::out);
1672}
1673
1674void DeviceHalAidl::setStreamOutCallback(
1675 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1676 setCallbackImpl(cookie, &Callbacks::out, cb);
1677}
1678
1679sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1680 void* cookie) {
1681 return getCallbackImpl(cookie, &Callbacks::event);
1682}
1683
1684void DeviceHalAidl::setStreamOutEventCallback(
1685 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1686 setCallbackImpl(cookie, &Callbacks::event, cb);
1687}
1688
1689sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1690 void* cookie) {
1691 return getCallbackImpl(cookie, &Callbacks::latency);
1692}
1693
1694void DeviceHalAidl::setStreamOutLatencyModeCallback(
1695 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1696 setCallbackImpl(cookie, &Callbacks::latency, cb);
1697}
1698
1699template<class C>
1700sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1701 std::lock_guard l(mLock);
1702 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1703 return ((it->second).*field).promote();
1704 }
1705 return nullptr;
1706}
1707template<class C>
1708void DeviceHalAidl::setCallbackImpl(
1709 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1710 std::lock_guard l(mLock);
1711 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1712 (it->second).*field = cb;
1713 }
1714}
1715
Mikhail Naganov31d46652023-01-10 18:29:25 +00001716} // namespace android