blob: de123f468042fb49a481cba67ba29cd92b75ffab [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) {
138 auto convertAudioPortFromMap = [](const Ports::value_type& pair) {
139 return ndk2cpp_AudioPort(pair.second);
140 };
141 return ::aidl::android::convertRange(mPorts.begin(), mPorts.end(), ports->begin(),
142 convertAudioPortFromMap);
143}
144
145status_t DeviceHalAidl::getAudioRoutes(std::vector<media::AudioRoute> *routes) {
146 *routes = VALUE_OR_RETURN_STATUS(
147 ::aidl::android::convertContainer<std::vector<media::AudioRoute>>(
148 mRoutes, ndk2cpp_AudioRoute));
149 return OK;
150}
151
Mikhail 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 }
292
293 ALOGW_IF(parameters.size() != 0, "%s: unknown parameters, ignored: \"%s\"",
294 __func__, parameters.toString().c_str());
Shunkai Yao51202502022-12-12 06:11:46 +0000295 return OK;
296}
297
Mikhail Naganov31d46652023-01-10 18:29:25 +0000298status_t DeviceHalAidl::getParameters(const String8& keys __unused, String8 *values) {
299 TIME_CHECK();
Mikhail 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
Eric Laurent8ed6d792023-06-29 11:44:54 +0200954status_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 Naganovf56ce782023-01-25 11:29:11 -08001259status_t DeviceHalAidl::findOrCreatePatch(
1260 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
1261 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
1262 requestedPatch.sourcePortConfigIds.end());
1263 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
1264 requestedPatch.sinkPortConfigIds.end());
1265 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
1266}
1267
1268status_t DeviceHalAidl::findOrCreatePatch(
1269 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
1270 AudioPatch* patch, bool* created) {
1271 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
1272 if (patchIt == mPatches.end()) {
1273 TIME_CHECK();
1274 AudioPatch requestedPatch, appliedPatch;
1275 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
1276 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
1277 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
1278 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
1279 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
1280 requestedPatch, &appliedPatch)));
1281 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
1282 *created = true;
1283 } else {
1284 *created = false;
1285 }
1286 *patch = patchIt->second;
1287 return OK;
1288}
1289
jiabin2248fa12023-04-27 22:04:16 +00001290status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device, const AudioConfig* config,
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001291 AudioPortConfig* portConfig, bool* created) {
1292 auto portConfigIt = findPortConfig(device);
1293 if (portConfigIt == mPortConfigs.end()) {
1294 auto portsIt = findPort(device);
1295 if (portsIt == mPorts.end()) {
1296 ALOGE("%s: device port for device %s is not found in the module %s",
1297 __func__, device.toString().c_str(), mInstance.c_str());
1298 return BAD_VALUE;
1299 }
1300 AudioPortConfig requestedPortConfig;
1301 requestedPortConfig.portId = portsIt->first;
jiabin2248fa12023-04-27 22:04:16 +00001302 if (config != nullptr) {
1303 setPortConfigFromConfig(&requestedPortConfig, *config);
1304 }
David Lia8f1e582023-03-30 21:08:06 +08001305 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1306 created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001307 } else {
1308 *created = false;
1309 }
1310 *portConfig = portConfigIt->second;
1311 return OK;
1312}
1313
1314status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001315 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001316 AudioSource source, const std::set<int32_t>& destinationPortIds,
1317 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001318 // These flags get removed one by one in this order when retrying port finding.
1319 static const std::vector<AudioInputFlags> kOptionalInputFlags{
1320 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001321 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001322 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001323 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
1324 AudioIoFlags matchFlags = flags.value();
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001325 auto portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001326 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
1327 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
1328 if (!isBitPositionFlagSet(
1329 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
1330 ++optionalInputFlagsIt;
1331 continue;
1332 }
1333 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
1334 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001335 portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001336 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
1337 "retried with flags %s", __func__, config.toString().c_str(),
1338 flags.value().toString().c_str(), mInstance.c_str(),
1339 matchFlags.toString().c_str());
1340 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001341 if (portsIt == mPorts.end()) {
1342 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001343 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001344 mInstance.c_str());
1345 return BAD_VALUE;
1346 }
1347 AudioPortConfig requestedPortConfig;
1348 requestedPortConfig.portId = portsIt->first;
1349 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001350 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001351 if (matchFlags.getTag() == AudioIoFlags::Tag::input
1352 && source != AudioSource::SYS_RESERVED_INVALID) {
1353 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
1354 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
1355 }
David Lia8f1e582023-03-30 21:08:06 +08001356 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1357 created));
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001358 } else if (!flags.has_value()) {
1359 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
1360 "and was not created as flags are not specified",
1361 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
1362 return BAD_VALUE;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001363 } else {
David Lia8f1e582023-03-30 21:08:06 +08001364 AudioPortConfig requestedPortConfig = portConfigIt->second;
1365 if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
1366 AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
1367 if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
1368 source != AudioSource::SYS_RESERVED_INVALID) {
1369 mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
1370 }
1371 }
1372
1373 if (requestedPortConfig != portConfigIt->second) {
1374 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1375 created));
1376 } else {
1377 *created = false;
1378 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001379 }
1380 *portConfig = portConfigIt->second;
1381 return OK;
1382}
1383
1384status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001385 const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
1386 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001387 using Tag = AudioPortExt::Tag;
1388 if (requestedPortConfig.ext.getTag() == Tag::mix) {
1389 if (const auto& p = requestedPortConfig;
1390 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001391 !p.format.has_value()) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001392 ALOGW("%s: provided mix port config is not fully specified: %s",
1393 __func__, p.toString().c_str());
1394 return BAD_VALUE;
1395 }
1396 AudioConfig config;
1397 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001398 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
1399 AudioPortMixExtUseCase::Tag::source ?
1400 requestedPortConfig.ext.get<Tag::mix>().usecase.
1401 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001402 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001403 requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
1404 portConfig, created);
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001405 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
1406 return findOrCreatePortConfig(
jiabin2248fa12023-04-27 22:04:16 +00001407 requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
1408 portConfig, created);
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001409 }
1410 ALOGW("%s: unsupported audio port config: %s",
1411 __func__, requestedPortConfig.toString().c_str());
1412 return BAD_VALUE;
1413}
1414
1415DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
1416 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
1417 return std::find_if(mPatches.begin(), mPatches.end(),
1418 [&](const auto& pair) {
1419 const auto& p = pair.second;
1420 std::set<int32_t> patchSrcs(
1421 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
1422 std::set<int32_t> patchSinks(
1423 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
1424 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
1425}
1426
1427DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001428 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1429 return mPorts.find(mDefaultInputPortId);
1430 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1431 return mPorts.find(mDefaultOutputPortId);
1432 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001433 return std::find_if(mPorts.begin(), mPorts.end(),
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001434 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001435}
1436
1437DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001438 const AudioConfig& config, const AudioIoFlags& flags,
1439 const std::set<int32_t>& destinationPortIds) {
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001440 auto belongsToProfile = [&config](const AudioProfile& prof) {
1441 return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
1442 (config.base.channelMask.getTag() == AudioChannelLayout::none ||
1443 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
1444 config.base.channelMask) != prof.channelMasks.end()) &&
1445 (config.base.sampleRate == 0 ||
1446 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
1447 config.base.sampleRate) != prof.sampleRates.end());
1448 };
jiabin2248fa12023-04-27 22:04:16 +00001449 static const std::vector<AudioOutputFlags> kOptionalOutputFlags{AudioOutputFlags::BIT_PERFECT};
1450 int optionalFlags = 0;
1451 auto flagMatches = [&flags, &optionalFlags](const AudioIoFlags& portFlags) {
1452 // Ports should be able to match if the optional flags are not requested.
1453 return portFlags == flags ||
1454 (portFlags.getTag() == AudioIoFlags::Tag::output &&
1455 AudioIoFlags::make<AudioIoFlags::Tag::output>(
1456 portFlags.get<AudioIoFlags::Tag::output>() &
1457 ~optionalFlags) == flags);
1458 };
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001459 auto matcher = [&](const auto& pair) {
1460 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001461 return p.ext.getTag() == AudioPortExt::Tag::mix &&
jiabin2248fa12023-04-27 22:04:16 +00001462 flagMatches(p.flags) &&
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001463 (destinationPortIds.empty() ||
1464 std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
1465 [&](const int32_t destId) { return mRoutingMatrix.count(
1466 std::make_pair(p.id, destId)) != 0; })) &&
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001467 (p.profiles.empty() ||
1468 std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
1469 p.profiles.end()); };
jiabin2248fa12023-04-27 22:04:16 +00001470 auto result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1471 if (result == mPorts.end() && flags.getTag() == AudioIoFlags::Tag::output) {
1472 auto optionalOutputFlagsIt = kOptionalOutputFlags.begin();
1473 while (result == mPorts.end() && optionalOutputFlagsIt != kOptionalOutputFlags.end()) {
1474 if (isBitPositionFlagSet(
1475 flags.get<AudioIoFlags::Tag::output>(), *optionalOutputFlagsIt)) {
1476 // If the flag is set by the request, it must be matched.
1477 ++optionalOutputFlagsIt;
1478 continue;
1479 }
1480 optionalFlags |= makeBitPositionFlagMask(*optionalOutputFlagsIt++);
1481 result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1482 ALOGI("%s: port for config %s, flags %s was not found in the module %s, "
1483 "retried with excluding optional flags %#x", __func__, config.toString().c_str(),
1484 flags.toString().c_str(), mInstance.c_str(), optionalFlags);
1485 }
1486 }
1487 return result;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001488}
1489
1490DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001491 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001492 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001493}
1494
1495DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001496 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001497 using Tag = AudioPortExt::Tag;
1498 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
1499 [&](const auto& pair) {
1500 const auto& p = pair.second;
1501 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
1502 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
1503 !p.format.has_value() || !p.flags.has_value(),
1504 "%s: stored mix port config is not fully specified: %s",
1505 __func__, p.toString().c_str());
1506 return p.ext.getTag() == Tag::mix &&
1507 isConfigEqualToPortConfig(config, p) &&
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001508 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001509 p.ext.template get<Tag::mix>().handle == ioHandle; });
1510}
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001511
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001512void DeviceHalAidl::resetPatch(int32_t patchId) {
1513 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1514 mPatches.erase(it);
1515 TIME_CHECK();
1516 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1517 ALOGE("%s: error while resetting patch %d: %s",
1518 __func__, patchId, status.getDescription().c_str());
1519 }
1520 return;
1521 }
1522 ALOGE("%s: patch id %d not found", __func__, patchId);
1523}
1524
1525void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1526 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1527 mPortConfigs.erase(it);
1528 TIME_CHECK();
1529 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1530 !status.isOk()) {
1531 ALOGE("%s: error while resetting port config %d: %s",
1532 __func__, portConfigId, status.getDescription().c_str());
1533 }
1534 return;
1535 }
1536 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1537}
1538
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001539void DeviceHalAidl::resetUnusedPatches() {
1540 // Since patches can be created independently of streams via 'createAudioPatch',
1541 // here we only clean up patches for released streams.
1542 for (auto it = mStreams.begin(); it != mStreams.end(); ) {
1543 if (auto streamSp = it->first.promote(); streamSp) {
1544 ++it;
1545 } else {
1546 resetPatch(it->second);
1547 it = mStreams.erase(it);
1548 }
1549 }
1550}
1551
1552void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
1553 resetUnusedPatches();
1554 resetUnusedPortConfigs();
1555}
1556
1557void DeviceHalAidl::resetUnusedPortConfigs() {
1558 // The assumption is that port configs are used to create patches
1559 // (or to open streams, but that involves creation of patches, too). Thus,
1560 // orphaned port configs can and should be reset.
1561 std::set<int32_t> portConfigIds;
1562 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
1563 std::inserter(portConfigIds, portConfigIds.end()),
1564 [](const auto& pcPair) { return pcPair.first; });
1565 for (const auto& p : mPatches) {
1566 for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
1567 for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
1568 }
jiabin2248fa12023-04-27 22:04:16 +00001569 for (int32_t id : mInitialPortConfigIds) {
1570 portConfigIds.erase(id);
1571 }
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001572 for (int32_t id : portConfigIds) resetPortConfig(id);
1573}
1574
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001575status_t DeviceHalAidl::updateRoutes() {
1576 TIME_CHECK();
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001577 RETURN_STATUS_IF_ERROR(
Mikhail Naganov2d814892023-04-24 13:06:04 -07001578 statusTFromBinderStatus(mModule->getAudioRoutes(&mRoutes)));
1579 ALOGW_IF(mRoutes.empty(), "%s: module %s returned an empty list of audio routes",
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001580 __func__, mInstance.c_str());
1581 mRoutingMatrix.clear();
Mikhail Naganov2d814892023-04-24 13:06:04 -07001582 for (const auto& r : mRoutes) {
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001583 for (auto portId : r.sourcePortIds) {
1584 mRoutingMatrix.emplace(r.sinkPortId, portId);
1585 mRoutingMatrix.emplace(portId, r.sinkPortId);
1586 }
1587 }
1588 return OK;
1589}
1590
Mikhail Naganovb0c55252023-02-08 16:59:41 -08001591void DeviceHalAidl::clearCallbacks(void* cookie) {
1592 std::lock_guard l(mLock);
1593 mCallbacks.erase(cookie);
1594}
1595
1596sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1597 return getCallbackImpl(cookie, &Callbacks::out);
1598}
1599
1600void DeviceHalAidl::setStreamOutCallback(
1601 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1602 setCallbackImpl(cookie, &Callbacks::out, cb);
1603}
1604
1605sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1606 void* cookie) {
1607 return getCallbackImpl(cookie, &Callbacks::event);
1608}
1609
1610void DeviceHalAidl::setStreamOutEventCallback(
1611 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1612 setCallbackImpl(cookie, &Callbacks::event, cb);
1613}
1614
1615sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1616 void* cookie) {
1617 return getCallbackImpl(cookie, &Callbacks::latency);
1618}
1619
1620void DeviceHalAidl::setStreamOutLatencyModeCallback(
1621 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1622 setCallbackImpl(cookie, &Callbacks::latency, cb);
1623}
1624
1625template<class C>
1626sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1627 std::lock_guard l(mLock);
1628 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1629 return ((it->second).*field).promote();
1630 }
1631 return nullptr;
1632}
1633template<class C>
1634void DeviceHalAidl::setCallbackImpl(
1635 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1636 std::lock_guard l(mLock);
1637 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1638 (it->second).*field = cb;
1639 }
1640}
1641
Mikhail Naganov31d46652023-01-10 18:29:25 +00001642} // namespace android