blob: 2447b18d358ec5dd70287d1cd7ad937554bc90d4 [file] [log] [blame]
Shunkai Yao51202502022-12-12 06:11:46 +00001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "DeviceHalAidl"
Mikhail Naganov89a9f742023-01-30 12:33:18 -080018// #define LOG_NDEBUG 0
Shunkai Yao51202502022-12-12 06:11:46 +000019
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080020#include <algorithm>
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080021
Mikhail Naganovdfd594e2023-02-08 16:59:41 -080022#include <aidl/android/hardware/audio/core/BnStreamCallback.h>
23#include <aidl/android/hardware/audio/core/BnStreamOutEventCallback.h>
Mikhail Naganovfab697c2023-01-11 19:33:13 +000024#include <aidl/android/hardware/audio/core/StreamDescriptor.h>
25#include <error/expected_utils.h>
26#include <media/AidlConversionCppNdk.h>
Mikhail Naganov25bc9a22023-04-21 18:48:16 -070027#include <media/AidlConversionNdkCpp.h>
Mikhail Naganovfab697c2023-01-11 19:33:13 +000028#include <media/AidlConversionUtil.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000029#include <mediautils/TimeCheck.h>
Mikhail Naganovae9063d2023-11-07 16:43:51 -080030#include <system/audio.h>
Mikhail Naganov89a9f742023-01-30 12:33:18 -080031#include <Utils.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000032#include <utils/Log.h>
Shunkai Yao51202502022-12-12 06:11:46 +000033
Mikhail Naganov31d46652023-01-10 18:29:25 +000034#include "DeviceHalAidl.h"
Mikhail Naganova82a69d2023-06-14 16:31:32 -070035#include "EffectHalAidl.h"
Mikhail Naganov31d46652023-01-10 18:29:25 +000036#include "StreamHalAidl.h"
37
Mikhail Naganovfab697c2023-01-11 19:33:13 +000038using aidl::android::aidl_utils::statusTFromBinderStatus;
Mikhail Naganovccc82112023-04-27 18:14:15 -070039using aidl::android::media::audio::common::Boolean;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080040using aidl::android::media::audio::common::AudioConfig;
41using aidl::android::media::audio::common::AudioDevice;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080042using aidl::android::media::audio::common::AudioDeviceType;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080043using aidl::android::media::audio::common::AudioIoFlags;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -080044using aidl::android::media::audio::common::AudioLatencyMode;
David Li9cf5e622023-03-21 00:51:10 +080045using aidl::android::media::audio::common::AudioMMapPolicy;
46using aidl::android::media::audio::common::AudioMMapPolicyInfo;
47using aidl::android::media::audio::common::AudioMMapPolicyType;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000048using aidl::android::media::audio::common::AudioMode;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080049using aidl::android::media::audio::common::AudioOutputFlags;
50using aidl::android::media::audio::common::AudioPort;
51using aidl::android::media::audio::common::AudioPortConfig;
David Li9cf5e622023-03-21 00:51:10 +080052using aidl::android::media::audio::common::AudioPortExt;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080053using aidl::android::media::audio::common::AudioSource;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000054using aidl::android::media::audio::common::Float;
David Li9cf5e622023-03-21 00:51:10 +080055using aidl::android::media::audio::common::Int;
56using aidl::android::media::audio::common::MicrophoneDynamicInfo;
57using aidl::android::media::audio::common::MicrophoneInfo;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -070058using aidl::android::media::audio::IHalAdapterVendorExtension;
Mikhail Naganov6352e822023-03-09 18:22:36 -080059using aidl::android::hardware::audio::common::getFrameSizeInBytes;
60using aidl::android::hardware::audio::common::isBitPositionFlagSet;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080061using aidl::android::hardware::audio::common::RecordTrackMetadata;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -070062using aidl::android::hardware::audio::core::sounddose::ISoundDose;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080063using aidl::android::hardware::audio::core::AudioPatch;
Mikhail Naganov289468a2023-03-29 10:06:15 -070064using aidl::android::hardware::audio::core::AudioRoute;
Mikhail Naganovccc82112023-04-27 18:14:15 -070065using aidl::android::hardware::audio::core::IBluetooth;
66using aidl::android::hardware::audio::core::IBluetoothA2dp;
67using aidl::android::hardware::audio::core::IBluetoothLe;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000068using aidl::android::hardware::audio::core::IModule;
69using aidl::android::hardware::audio::core::ITelephony;
Mikhail Naganove93a0862023-03-15 17:06:59 -070070using aidl::android::hardware::audio::core::ModuleDebug;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -070071using aidl::android::hardware::audio::core::VendorParameter;
Mikhail Naganov31d46652023-01-10 18:29:25 +000072
73namespace android {
74
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080075namespace {
76
Mikhail Naganovf83b9742023-04-24 13:06:04 -070077// Note: these converters are for types defined in different AIDL files. Although these
78// AIDL files are copies of each other, however formally these are different types
79// thus we don't use a conversion via a parcelable.
80ConversionResult<media::AudioRoute> ndk2cpp_AudioRoute(const AudioRoute& ndk) {
81 media::AudioRoute cpp;
82 cpp.sourcePortIds.insert(
83 cpp.sourcePortIds.end(), ndk.sourcePortIds.begin(), ndk.sourcePortIds.end());
84 cpp.sinkPortId = ndk.sinkPortId;
85 cpp.isExclusive = ndk.isExclusive;
David Li9cf5e622023-03-21 00:51:10 +080086 return cpp;
87}
88
Mikhail Naganov1fba38c2023-05-03 17:45:36 -070089template<typename T>
90std::shared_ptr<T> retrieveSubInterface(const std::shared_ptr<IModule>& module,
91 ::ndk::ScopedAStatus (IModule::*getT)(std::shared_ptr<T>*)) {
92 if (module != nullptr) {
93 std::shared_ptr<T> instance;
94 if (auto status = (module.get()->*getT)(&instance); status.isOk()) {
95 return instance;
96 }
97 }
98 return nullptr;
99}
100
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800101} // namespace
102
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700103DeviceHalAidl::DeviceHalAidl(const std::string& instance, const std::shared_ptr<IModule>& module,
104 const std::shared_ptr<IHalAdapterVendorExtension>& vext)
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700105 : ConversionHelperAidl("DeviceHalAidl"),
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700106 mInstance(instance), mModule(module), mVendorExt(vext),
Mikhail Naganovccc82112023-04-27 18:14:15 -0700107 mTelephony(retrieveSubInterface<ITelephony>(module, &IModule::getTelephony)),
108 mBluetooth(retrieveSubInterface<IBluetooth>(module, &IModule::getBluetooth)),
109 mBluetoothA2dp(retrieveSubInterface<IBluetoothA2dp>(module, &IModule::getBluetoothA2dp)),
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700110 mBluetoothLe(retrieveSubInterface<IBluetoothLe>(module, &IModule::getBluetoothLe)),
111 mSoundDose(retrieveSubInterface<ISoundDose>(module, &IModule::getSoundDose)),
112 mMapper(instance, module), mMapperAccessor(mMapper, mLock) {
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700113}
114
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700115status_t DeviceHalAidl::getAudioPorts(std::vector<media::audio::common::AudioPort> *ports) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700116 std::lock_guard l(mLock);
117 return mMapper.getAudioPorts(ports, ndk2cpp_AudioPort);
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700118}
119
120status_t DeviceHalAidl::getAudioRoutes(std::vector<media::AudioRoute> *routes) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700121 std::lock_guard l(mLock);
122 return mMapper.getAudioRoutes(routes, ndk2cpp_AudioRoute);
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700123}
124
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700125status_t DeviceHalAidl::getSupportedModes(std::vector<media::audio::common::AudioMode> *modes) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700126 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700127 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700128 if (mModule == nullptr) return NO_INIT;
129 if (mTelephony == nullptr) return INVALID_OPERATION;
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700130 if (modes == nullptr) {
131 return BAD_VALUE;
132 }
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700133 std::vector<AudioMode> aidlModes;
134 RETURN_STATUS_IF_ERROR(
135 statusTFromBinderStatus(mTelephony->getSupportedAudioModes(&aidlModes)));
136 *modes = VALUE_OR_RETURN_STATUS(
137 ::aidl::android::convertContainer<std::vector<media::audio::common::AudioMode>>(
138 aidlModes, ndk2cpp_AudioMode));
139 return OK;
140}
141
Mikhail Naganov31d46652023-01-10 18:29:25 +0000142status_t DeviceHalAidl::getSupportedDevices(uint32_t*) {
143 // Obsolete.
144 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +0000145}
146
147status_t DeviceHalAidl::initCheck() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700148 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800149 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000150 if (mModule == nullptr) return NO_INIT;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700151 std::lock_guard l(mLock);
152 return mMapper.initialize();
Shunkai Yao51202502022-12-12 06:11:46 +0000153}
154
155status_t DeviceHalAidl::setVoiceVolume(float volume) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700156 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000157 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700158 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700159 if (mTelephony == nullptr) return INVALID_OPERATION;
160 ITelephony::TelecomConfig inConfig{ .voiceVolume = Float{volume} }, outConfig;
161 RETURN_STATUS_IF_ERROR(
162 statusTFromBinderStatus(mTelephony->setTelecomConfig(inConfig, &outConfig)));
163 ALOGW_IF(outConfig.voiceVolume.has_value() && volume != outConfig.voiceVolume.value().value,
164 "%s: the resulting voice volume %f is not the same as requested %f",
165 __func__, outConfig.voiceVolume.value().value, volume);
166 return OK;
Shunkai Yao51202502022-12-12 06:11:46 +0000167}
168
169status_t DeviceHalAidl::setMasterVolume(float volume) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700170 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000171 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700172 if (mModule == nullptr) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000173 return statusTFromBinderStatus(mModule->setMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000174}
175
176status_t DeviceHalAidl::getMasterVolume(float *volume) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700177 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000178 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700179 if (mModule == nullptr) return NO_INIT;
180 if (volume == nullptr) {
181 return BAD_VALUE;
182 }
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000183 return statusTFromBinderStatus(mModule->getMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000184}
185
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000186status_t DeviceHalAidl::setMode(audio_mode_t mode) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700187 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000188 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700189 if (mModule == nullptr) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000190 AudioMode audioMode = VALUE_OR_FATAL(::aidl::android::legacy2aidl_audio_mode_t_AudioMode(mode));
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700191 if (mTelephony != nullptr) {
192 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mTelephony->switchAudioMode(audioMode)));
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000193 }
194 return statusTFromBinderStatus(mModule->updateAudioMode(audioMode));
Shunkai Yao51202502022-12-12 06:11:46 +0000195}
196
197status_t DeviceHalAidl::setMicMute(bool state) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700198 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000199 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700200 if (mModule == nullptr) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000201 return statusTFromBinderStatus(mModule->setMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000202}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000203
Shunkai Yao51202502022-12-12 06:11:46 +0000204status_t DeviceHalAidl::getMicMute(bool *state) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700205 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000206 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700207 if (mModule == nullptr) return NO_INIT;
208 if (state == nullptr) {
209 return BAD_VALUE;
210 }
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000211 return statusTFromBinderStatus(mModule->getMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000212}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000213
Shunkai Yao51202502022-12-12 06:11:46 +0000214status_t DeviceHalAidl::setMasterMute(bool state) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700215 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000216 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700217 if (mModule == nullptr) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000218 return statusTFromBinderStatus(mModule->setMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000219}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000220
Shunkai Yao51202502022-12-12 06:11:46 +0000221status_t DeviceHalAidl::getMasterMute(bool *state) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700222 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000223 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700224 if (mModule == nullptr) return NO_INIT;
225 if (state == nullptr) {
226 return BAD_VALUE;
227 }
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000228 return statusTFromBinderStatus(mModule->getMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000229}
230
Mikhail Naganovccc82112023-04-27 18:14:15 -0700231status_t DeviceHalAidl::setParameters(const String8& kvPairs) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700232 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
233 TIME_CHECK();
234 if (mModule == nullptr) return NO_INIT;
Mikhail Naganovccc82112023-04-27 18:14:15 -0700235 AudioParameter parameters(kvPairs);
236 ALOGD("%s: parameters: \"%s\"", __func__, parameters.toString().c_str());
237
238 if (status_t status = filterAndUpdateBtA2dpParameters(parameters); status != OK) {
239 ALOGW("%s: filtering or updating BT A2DP parameters failed: %d", __func__, status);
240 }
241 if (status_t status = filterAndUpdateBtHfpParameters(parameters); status != OK) {
242 ALOGW("%s: filtering or updating BT HFP parameters failed: %d", __func__, status);
243 }
244 if (status_t status = filterAndUpdateBtLeParameters(parameters); status != OK) {
245 ALOGW("%s: filtering or updating BT LE parameters failed: %d", __func__, status);
246 }
247 if (status_t status = filterAndUpdateBtScoParameters(parameters); status != OK) {
248 ALOGW("%s: filtering or updating BT SCO parameters failed: %d", __func__, status);
249 }
Mikhail Naganove92c34b2023-05-31 14:24:48 -0700250 if (status_t status = filterAndUpdateScreenParameters(parameters); status != OK) {
251 ALOGW("%s: filtering or updating screen parameters failed: %d", __func__, status);
252 }
Mikhail Naganovb9a81312023-07-18 13:55:34 -0700253 if (status_t status = filterAndUpdateTelephonyParameters(parameters); status != OK) {
254 ALOGW("%s: filtering or updating telephony parameters failed: %d", __func__, status);
255 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700256 return parseAndSetVendorParameters(mVendorExt, mModule, parameters);
Shunkai Yao51202502022-12-12 06:11:46 +0000257}
258
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700259status_t DeviceHalAidl::getParameters(const String8& keys, String8 *values) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700260 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000261 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700262 if (mModule == nullptr) return NO_INIT;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700263 if (values == nullptr) {
264 return BAD_VALUE;
265 }
266 AudioParameter parameterKeys(keys), result;
267 if (status_t status = filterAndRetrieveBtA2dpParameters(parameterKeys, &result); status != OK) {
268 ALOGW("%s: filtering or retrieving BT A2DP parameters failed: %d", __func__, status);
269 }
Eric Laurent7e3c0832023-11-30 15:04:50 +0100270 if (status_t status = filterAndRetrieveBtLeParameters(parameterKeys, &result); status != OK) {
271 ALOGW("%s: filtering or retrieving BT LE parameters failed: %d", __func__, status);
272 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700273 *values = result.toString();
274 return parseAndGetVendorParameters(mVendorExt, mModule, parameterKeys, values);
Shunkai Yao51202502022-12-12 06:11:46 +0000275}
276
Mikhail Naganovd5b643f2024-02-15 11:51:26 -0800277status_t DeviceHalAidl::getInputBufferSize(struct audio_config* config, size_t* size) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800278 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800279 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700280 if (mModule == nullptr) return NO_INIT;
281 if (config == nullptr || size == nullptr) {
282 return BAD_VALUE;
283 }
Mikhail Naganovd5b643f2024-02-15 11:51:26 -0800284 constexpr bool isInput = true;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800285 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
Mikhail Naganovd5b643f2024-02-15 11:51:26 -0800286 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, isInput));
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800287 AudioDevice aidlDevice;
288 aidlDevice.type.type = AudioDeviceType::IN_DEFAULT;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800289 AudioSource aidlSource = AudioSource::DEFAULT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800290 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
291 AudioPortConfig mixPortConfig;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700292 Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700293 AudioPatch aidlPatch;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700294 {
295 std::lock_guard l(mLock);
296 RETURN_STATUS_IF_ERROR(mMapper.prepareToOpenStream(
297 0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
298 &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
299 }
Mikhail Naganovd5b643f2024-02-15 11:51:26 -0800300 *config = VALUE_OR_RETURN_STATUS(
301 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(aidlConfig, isInput));
302 if (mixPortConfig.id == 0) return BAD_VALUE; // HAL suggests a different config.
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800303 *size = aidlConfig.frameCount *
304 getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
305 // Do not disarm cleanups to release temporary port configs.
306 return OK;
307}
308
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800309namespace {
310
311class StreamCallbackBase {
312 protected:
313 explicit StreamCallbackBase(const sp<CallbackBroker>& broker) : mBroker(broker) {}
314 public:
315 void* getCookie() const { return mCookie; }
316 void setCookie(void* cookie) { mCookie = cookie; }
317 sp<CallbackBroker> getBroker() const {
318 if (void* cookie = mCookie; cookie != nullptr) return mBroker.promote();
319 return nullptr;
320 }
321 private:
322 const wp<CallbackBroker> mBroker;
323 std::atomic<void*> mCookie;
324};
325
326template<class C>
327class StreamCallbackBaseHelper {
328 protected:
329 explicit StreamCallbackBaseHelper(const StreamCallbackBase& base) : mBase(base) {}
330 sp<C> getCb(const sp<CallbackBroker>& broker, void* cookie);
331 using CbRef = const sp<C>&;
332 ndk::ScopedAStatus runCb(const std::function<void(CbRef cb)>& f) {
333 if (auto cb = getCb(mBase.getBroker(), mBase.getCookie()); cb != nullptr) f(cb);
334 return ndk::ScopedAStatus::ok();
335 }
336 private:
337 const StreamCallbackBase& mBase;
338};
339
340template<>
341sp<StreamOutHalInterfaceCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>::getCb(
342 const sp<CallbackBroker>& broker, void* cookie) {
343 if (broker != nullptr) return broker->getStreamOutCallback(cookie);
344 return nullptr;
345}
346
347template<>
348sp<StreamOutHalInterfaceEventCallback>
349StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::getCb(
350 const sp<CallbackBroker>& broker, void* cookie) {
351 if (broker != nullptr) return broker->getStreamOutEventCallback(cookie);
352 return nullptr;
353}
354
355template<>
356sp<StreamOutHalInterfaceLatencyModeCallback>
357StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::getCb(
358 const sp<CallbackBroker>& broker, void* cookie) {
359 if (broker != nullptr) return broker->getStreamOutLatencyModeCallback(cookie);
360 return nullptr;
361}
362
363/*
364Note on the callback ownership.
365
366In the Binder ownership model, the server implementation is kept alive
367as long as there is any client (proxy object) alive. This is done by
368incrementing the refcount of the server-side object by the Binder framework.
369When it detects that the last client is gone, it decrements the refcount back.
370
371Thus, it is not needed to keep any references to StreamCallback on our
372side (after we have sent an instance to the client), because we are
373the server-side. The callback object will be kept alive as long as the HAL server
374holds a strong ref to IStreamCallback proxy.
375*/
376
377class OutputStreamCallbackAidl : public StreamCallbackBase,
378 public StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>,
379 public ::aidl::android::hardware::audio::core::BnStreamCallback {
380 public:
381 explicit OutputStreamCallbackAidl(const sp<CallbackBroker>& broker)
382 : StreamCallbackBase(broker),
383 StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>(
384 *static_cast<StreamCallbackBase*>(this)) {}
385 ndk::ScopedAStatus onTransferReady() override {
386 return runCb([](CbRef cb) { cb->onWriteReady(); });
387 }
388 ndk::ScopedAStatus onError() override {
389 return runCb([](CbRef cb) { cb->onError(); });
390 }
391 ndk::ScopedAStatus onDrainReady() override {
392 return runCb([](CbRef cb) { cb->onDrainReady(); });
393 }
394};
395
396class OutputStreamEventCallbackAidl :
397 public StreamCallbackBase,
398 public StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>,
399 public StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>,
400 public ::aidl::android::hardware::audio::core::BnStreamOutEventCallback {
401 public:
402 explicit OutputStreamEventCallbackAidl(const sp<CallbackBroker>& broker)
403 : StreamCallbackBase(broker),
404 StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>(
405 *static_cast<StreamCallbackBase*>(this)),
406 StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>(
407 *static_cast<StreamCallbackBase*>(this)) {}
Ryan Prichard78c5e452024-02-08 16:16:57 -0800408 ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& halMetadata) override {
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800409 return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb(
410 [&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); });
411 }
412 ndk::ScopedAStatus onRecommendedLatencyModeChanged(
413 const std::vector<AudioLatencyMode>& in_modes) override {
414 auto halModes = VALUE_OR_FATAL(
415 ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
416 in_modes,
417 ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
418 return StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::runCb(
419 [&halModes](auto cb) { cb->onRecommendedLatencyModeChanged(halModes); });
420 }
421};
422
423} // namespace
424
Mikhail Naganov31d46652023-01-10 18:29:25 +0000425status_t DeviceHalAidl::openOutputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800426 audio_io_handle_t handle, audio_devices_t devices,
427 audio_output_flags_t flags, struct audio_config* config,
428 const char* address,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000429 sp<StreamOutHalInterface>* outStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800430 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700431 TIME_CHECK();
432 if (mModule == nullptr) return NO_INIT;
433 if (outStream == nullptr || config == nullptr) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000434 return BAD_VALUE;
435 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700436 constexpr bool isInput = false;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800437 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
438 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
439 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700440 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, isInput));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800441 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
442 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
443 int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
444 ::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
445 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
446 AudioPortConfig mixPortConfig;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700447 AudioPatch aidlPatch;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700448 Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
449 {
450 std::lock_guard l(mLock);
451 RETURN_STATUS_IF_ERROR(mMapper.prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
452 AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
453 &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
454 }
455 *config = VALUE_OR_RETURN_STATUS(
456 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(aidlConfig, isInput));
Mikhail Naganovca92a5c2023-12-07 14:00:48 -0800457 if (mixPortConfig.id == 0) return BAD_VALUE; // HAL suggests a different config.
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800458 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
459 args.portConfigId = mixPortConfig.id;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800460 const bool isOffload = isBitPositionFlagSet(
461 aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD);
462 std::shared_ptr<OutputStreamCallbackAidl> streamCb;
463 if (isOffload) {
464 streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
465 }
466 auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
467 if (isOffload) {
468 args.offloadInfo = aidlConfig.offloadInfo;
469 args.callback = streamCb;
470 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800471 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800472 args.eventCallback = eventCb;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800473 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
474 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800475 StreamContextAidl context(ret.desc, isOffload);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800476 if (!context.isValid()) {
477 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
478 __func__, ret.desc.toString().c_str());
479 return NO_INIT;
480 }
Mikhail Naganov8065bfd2024-03-25 14:59:49 -0700481 auto stream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700482 std::move(ret.stream), mVendorExt, this /*callbackBroker*/);
Mikhail Naganov8065bfd2024-03-25 14:59:49 -0700483 *outStream = stream;
484 /* StreamOutHalInterface* */ void* cbCookie = (*outStream).get();
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800485 {
486 std::lock_guard l(mLock);
487 mCallbacks.emplace(cbCookie, Callbacks{});
Mikhail Naganov78f7f9a2023-11-16 15:49:23 -0800488 mMapper.addStream(*outStream, mixPortConfig.id, aidlPatch.id);
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800489 }
Mikhail Naganov8065bfd2024-03-25 14:59:49 -0700490 if (streamCb) {
491 streamCb->setCookie(cbCookie);
492 // Although StreamOutHalAidl implements StreamOutHalInterfaceCallback,
493 // we always go via the CallbackBroker for consistency.
494 setStreamOutCallback(cbCookie, stream);
495 }
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800496 eventCb->setCookie(cbCookie);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800497 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000498 return OK;
499}
500
Mikhail Naganov31d46652023-01-10 18:29:25 +0000501status_t DeviceHalAidl::openInputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800502 audio_io_handle_t handle, audio_devices_t devices,
503 struct audio_config* config, audio_input_flags_t flags,
504 const char* address, audio_source_t source,
505 audio_devices_t outputDevice, const char* outputDeviceAddress,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000506 sp<StreamInHalInterface>* inStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800507 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700508 TIME_CHECK();
509 if (mModule == nullptr) return NO_INIT;
510 if (inStream == nullptr || config == nullptr) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000511 return BAD_VALUE;
512 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700513 constexpr bool isInput = true;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800514 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
515 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
516 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700517 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, isInput));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800518 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
519 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
520 int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
521 ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
522 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
523 AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
524 ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
525 AudioPortConfig mixPortConfig;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700526 AudioPatch aidlPatch;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700527 Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
528 {
529 std::lock_guard l(mLock);
530 RETURN_STATUS_IF_ERROR(mMapper.prepareToOpenStream(
531 aidlHandle, aidlDevice, aidlFlags, aidlSource,
532 &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
533 }
534 *config = VALUE_OR_RETURN_STATUS(
535 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(aidlConfig, isInput));
Mikhail Naganovca92a5c2023-12-07 14:00:48 -0800536 if (mixPortConfig.id == 0) return BAD_VALUE; // HAL suggests a different config.
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800537 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
538 args.portConfigId = mixPortConfig.id;
539 RecordTrackMetadata aidlTrackMetadata{
540 .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
541 if (outputDevice != AUDIO_DEVICE_NONE) {
542 aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
543 ::aidl::android::legacy2aidl_audio_device_AudioDevice(
544 outputDevice, outputDeviceAddress));
545 }
546 args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
547 args.bufferSizeFrames = aidlConfig.frameCount;
548 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
549 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800550 StreamContextAidl context(ret.desc, false /*isAsynchronous*/);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800551 if (!context.isValid()) {
552 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
553 __func__, ret.desc.toString().c_str());
554 return NO_INIT;
555 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700556 *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700557 std::move(ret.stream), mVendorExt, this /*micInfoProvider*/);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700558 {
559 std::lock_guard l(mLock);
Mikhail Naganov78f7f9a2023-11-16 15:49:23 -0800560 mMapper.addStream(*inStream, mixPortConfig.id, aidlPatch.id);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700561 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800562 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000563 return OK;
564}
565
566status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700567 if (supportsPatches == nullptr) {
568 return BAD_VALUE;
569 }
Shunkai Yao51202502022-12-12 06:11:46 +0000570 *supportsPatches = true;
571 return OK;
572}
573
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800574status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
575 const struct audio_port_config* sources,
576 unsigned int num_sinks,
577 const struct audio_port_config* sinks,
578 audio_patch_handle_t* patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800579 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000580 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700581 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800582 if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
583 sources == nullptr || sinks == nullptr || patch == nullptr) {
584 return BAD_VALUE;
585 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800586 // When the patch handle (*patch) is AUDIO_PATCH_HANDLE_NONE, it means
587 // the framework wants to create a new patch. The handle has to be generated
588 // by the HAL. Since handles generated this way can only be unique within
589 // a HAL module, the framework generates a globally unique handle, and maps
590 // it on the <HAL module, patch handle> pair.
591 // When the patch handle is set, it meant the framework intends to update
592 // an existing patch.
593 //
594 // This behavior corresponds to HAL module behavior, with the only difference
595 // that the HAL module uses `int32_t` for patch IDs. The following assert ensures
596 // that both the framework and the HAL use the same value for "no ID":
597 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800598
599 // Upon conversion, mix port configs contain audio configuration, while
600 // device port configs contain device address. This data is used to find
601 // or create HAL configs.
602 std::vector<AudioPortConfig> aidlSources, aidlSinks;
603 for (unsigned int i = 0; i < num_sources; ++i) {
604 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
605 sources[i].role, sources[i].type)) ==
606 ::aidl::android::AudioPortDirection::INPUT;
607 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
608 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
609 sources[i], isInput, 0)));
610 }
611 for (unsigned int i = 0; i < num_sinks; ++i) {
612 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
613 sinks[i].role, sinks[i].type)) ==
614 ::aidl::android::AudioPortDirection::INPUT;
615 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
616 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
617 sinks[i], isInput, 0)));
618 }
Mikhail Naganov6b5da722024-03-14 12:59:32 -0700619 int32_t aidlPatchId = static_cast<int32_t>(*patch);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700620 Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
621 {
622 std::lock_guard l(mLock);
Mikhail Naganov6b5da722024-03-14 12:59:32 -0700623 // Check for patches that only exist for the framework, or have different HAL patch ID.
624 if (int32_t aidlHalPatchId = mMapper.findFwkPatch(aidlPatchId); aidlHalPatchId != 0) {
625 if (aidlHalPatchId == aidlPatchId) {
626 // This patch was previously released by the HAL. Thus we need to pass '0'
627 // to the HAL to obtain a new patch.
628 int32_t newAidlPatchId = 0;
629 RETURN_STATUS_IF_ERROR(mMapper.createOrUpdatePatch(
630 aidlSources, aidlSinks, &newAidlPatchId, &cleanups));
631 mMapper.updateFwkPatch(aidlPatchId, newAidlPatchId);
632 } else {
633 RETURN_STATUS_IF_ERROR(mMapper.createOrUpdatePatch(
634 aidlSources, aidlSinks, &aidlHalPatchId, &cleanups));
635 }
636 } else {
637 RETURN_STATUS_IF_ERROR(mMapper.createOrUpdatePatch(
638 aidlSources, aidlSinks, &aidlPatchId, &cleanups));
639 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800640 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700641 *patch = static_cast<audio_patch_handle_t>(aidlPatchId);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800642 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000643 return OK;
644}
645
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800646status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800647 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000648 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700649 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800650 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
651 if (patch == AUDIO_PATCH_HANDLE_NONE) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800652 return BAD_VALUE;
653 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700654 std::lock_guard l(mLock);
Mikhail Naganov6b5da722024-03-14 12:59:32 -0700655 // Check for patches that only exist for the framework, or have different HAL patch ID.
656 int32_t aidlPatchId = static_cast<int32_t>(patch);
657 if (int32_t aidlHalPatchId = mMapper.findFwkPatch(aidlPatchId); aidlHalPatchId != 0) {
658 if (aidlHalPatchId == aidlPatchId) {
659 // This patch was previously released by the HAL, just need to finish its removal.
660 mMapper.eraseFwkPatch(aidlPatchId);
661 return OK;
662 } else {
663 // This patch has a HAL patch ID which is different
664 aidlPatchId = aidlHalPatchId;
665 }
666 }
667 RETURN_STATUS_IF_ERROR(mMapper.releaseAudioPatch(aidlPatchId));
Shunkai Yao51202502022-12-12 06:11:46 +0000668 return OK;
669}
670
Mikhail Naganove93a0862023-03-15 17:06:59 -0700671status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700672 if (port == nullptr) {
673 return BAD_VALUE;
674 }
675 audio_port_v7 portV7;
676 audio_populate_audio_port_v7(port, &portV7);
677 RETURN_STATUS_IF_ERROR(getAudioPort(&portV7));
678 return audio_populate_audio_port(&portV7, port) ? OK : BAD_VALUE;
679}
680
681status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
682 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
683 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700684 if (mModule == nullptr) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700685 if (port == nullptr) {
686 return BAD_VALUE;
687 }
688 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
689 ::aidl::android::AudioPortDirection::INPUT;
690 auto aidlPort = VALUE_OR_RETURN_STATUS(
691 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
692 if (aidlPort.ext.getTag() != AudioPortExt::device) {
693 ALOGE("%s: provided port is not a device port (module %s): %s",
694 __func__, mInstance.c_str(), aidlPort.toString().c_str());
695 return BAD_VALUE;
696 }
697 const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
698 // It seems that we don't have to call HAL since all valid ports have been added either
699 // during initialization, or while handling connection of an external device.
Mikhail Naganove93a0862023-03-15 17:06:59 -0700700 const int32_t fwkId = aidlPort.id;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700701 {
702 std::lock_guard l(mLock);
703 RETURN_STATUS_IF_ERROR(mMapper.getAudioPortCached(matchDevice, &aidlPort));
704 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700705 aidlPort.id = fwkId;
706 *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
707 aidlPort, isInput));
708 return OK;
709}
710
jiabin12537fc2023-10-12 17:56:08 +0000711status_t DeviceHalAidl::getAudioMixPort(const struct audio_port_v7 *devicePort,
712 struct audio_port_v7 *mixPort) {
713 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700714 TIME_CHECK();
715 if (mModule == nullptr) return NO_INIT;
716 if (devicePort == nullptr || mixPort == nullptr ||
717 devicePort->type != AUDIO_PORT_TYPE_DEVICE || mixPort->type != AUDIO_PORT_TYPE_MIX) {
jiabin12537fc2023-10-12 17:56:08 +0000718 return BAD_VALUE;
719 }
720 const int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
721 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(mixPort->ext.mix.handle));
jiabin12537fc2023-10-12 17:56:08 +0000722 AudioPort port;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700723 {
724 std::lock_guard l(mLock);
725 RETURN_STATUS_IF_ERROR(mMapper.getAudioMixPort(aidlHandle, &port));
jiabin12537fc2023-10-12 17:56:08 +0000726 }
727 const bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
728 mixPort->role, mixPort->type)) == ::aidl::android::AudioPortDirection::INPUT;
729 *mixPort = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
730 port, isInput));
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700731 return OK;
jiabin12537fc2023-10-12 17:56:08 +0000732}
733
Mikhail Naganove93a0862023-03-15 17:06:59 -0700734status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
735 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
736 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700737 if (mModule == nullptr) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700738 if (config == nullptr) {
739 return BAD_VALUE;
740 }
741 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
742 config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
743 AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
744 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
745 *config, isInput, 0 /*portId*/));
746 AudioPortConfig portConfig;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700747 std::lock_guard l(mLock);
Mikhail Naganovca92a5c2023-12-07 14:00:48 -0800748 return mMapper.setPortConfig(requestedPortConfig, std::set<int32_t>(), &portConfig);
Shunkai Yao51202502022-12-12 06:11:46 +0000749}
750
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800751MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700752 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
753 TIME_CHECK();
754 if (!mModule) return {};
755 std::lock_guard l(mLock);
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800756 if (mMicrophones.status == Microphones::Status::UNKNOWN) {
757 TIME_CHECK();
758 std::vector<MicrophoneInfo> aidlInfo;
759 status_t status = statusTFromBinderStatus(mModule->getMicrophones(&aidlInfo));
760 if (status == OK) {
761 mMicrophones.status = Microphones::Status::QUERIED;
762 mMicrophones.info = std::move(aidlInfo);
763 } else if (status == INVALID_OPERATION) {
764 mMicrophones.status = Microphones::Status::NOT_SUPPORTED;
765 } else {
766 ALOGE("%s: Unexpected status from 'IModule.getMicrophones': %d", __func__, status);
767 return {};
768 }
769 }
770 if (mMicrophones.status == Microphones::Status::QUERIED) {
771 return &mMicrophones.info;
772 }
773 return {}; // NOT_SUPPORTED
774}
775
Shunkai Yao51202502022-12-12 06:11:46 +0000776status_t DeviceHalAidl::getMicrophones(
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800777 std::vector<audio_microphone_characteristic_t>* microphones) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700778 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
779 TIME_CHECK();
780 if (mModule == nullptr) return NO_INIT;
781 if (microphones == nullptr) {
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800782 return BAD_VALUE;
783 }
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800784 auto staticInfo = getMicrophoneInfo();
785 if (!staticInfo) return INVALID_OPERATION;
786 std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
787 emptyDynamicInfo.reserve(staticInfo->size());
788 std::transform(staticInfo->begin(), staticInfo->end(), std::back_inserter(emptyDynamicInfo),
789 [](const auto& info) { return MicrophoneDynamicInfo{ .id = info.id }; });
790 *microphones = VALUE_OR_RETURN_STATUS(
791 ::aidl::android::convertContainers<std::vector<audio_microphone_characteristic_t>>(
792 *staticInfo, emptyDynamicInfo,
793 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t)
794 );
Shunkai Yao51202502022-12-12 06:11:46 +0000795 return OK;
796}
797
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700798status_t DeviceHalAidl::addDeviceEffect(
799 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700800 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700801 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700802 if (mModule == nullptr) return NO_INIT;
803 if (device == nullptr || effect == nullptr) {
Shunkai Yao51202502022-12-12 06:11:46 +0000804 return BAD_VALUE;
805 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700806 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
807 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
808 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
809 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
810 *device, isInput, 0));
811 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
812 ALOGE("%s: provided port config is not a device port config: %s",
813 __func__, requestedPortConfig.toString().c_str());
814 return BAD_VALUE;
815 }
816 AudioPortConfig devicePortConfig;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700817 Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
818 {
819 std::lock_guard l(mLock);
Mikhail Naganovca92a5c2023-12-07 14:00:48 -0800820 RETURN_STATUS_IF_ERROR(mMapper.setPortConfig(
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700821 requestedPortConfig, {} /*destinationPortIds*/, &devicePortConfig, &cleanups));
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700822 }
823 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
824 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->addDeviceEffect(
825 devicePortConfig.id, aidlEffect->getIEffect())));
826 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000827 return OK;
828}
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700829status_t DeviceHalAidl::removeDeviceEffect(
830 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700831 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700832 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700833 if (mModule == nullptr) return NO_INIT;
834 if (device == nullptr || effect == nullptr) {
Shunkai Yao51202502022-12-12 06:11:46 +0000835 return BAD_VALUE;
836 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700837 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
838 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
839 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
840 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
841 *device, isInput, 0));
842 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
843 ALOGE("%s: provided port config is not a device port config: %s",
844 __func__, requestedPortConfig.toString().c_str());
845 return BAD_VALUE;
846 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700847 AudioPortConfig devicePortConfig;
848 {
849 std::lock_guard l(mLock);
850 RETURN_STATUS_IF_ERROR(mMapper.findPortConfig(
851 requestedPortConfig.ext.get<AudioPortExt::Tag::device>().device,
852 &devicePortConfig));
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700853 }
854 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
855 return statusTFromBinderStatus(mModule->removeDeviceEffect(
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700856 devicePortConfig.id, aidlEffect->getIEffect()));
Shunkai Yao51202502022-12-12 06:11:46 +0000857}
858
859status_t DeviceHalAidl::getMmapPolicyInfos(
David Li9cf5e622023-03-21 00:51:10 +0800860 media::audio::common::AudioMMapPolicyType policyType,
861 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700862 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000863 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700864 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov25bc9a22023-04-21 18:48:16 -0700865 AudioMMapPolicyType mmapPolicyType = VALUE_OR_RETURN_STATUS(
866 cpp2ndk_AudioMMapPolicyType(policyType));
David Li9cf5e622023-03-21 00:51:10 +0800867
868 std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
869
870 if (status_t status = statusTFromBinderStatus(
871 mModule->getMmapPolicyInfos(mmapPolicyType, &mmapPolicyInfos)); status != OK) {
872 return status;
873 }
874
875 *policyInfos = VALUE_OR_RETURN_STATUS(
876 convertContainer<std::vector<media::audio::common::AudioMMapPolicyInfo>>(
877 mmapPolicyInfos, ndk2cpp_AudioMMapPolicyInfo));
Shunkai Yao51202502022-12-12 06:11:46 +0000878 return OK;
879}
880
881int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700882 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000883 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700884 if (mModule == nullptr) return NO_INIT;
David Li9cf5e622023-03-21 00:51:10 +0800885 int32_t mixerBurstCount = 0;
886 if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
887 return mixerBurstCount;
888 }
889 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000890}
891
892int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700893 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000894 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700895 if (mModule == nullptr) return NO_INIT;
David Li9cf5e622023-03-21 00:51:10 +0800896 int32_t hardwareBurstMinUsec = 0;
897 if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
898 return hardwareBurstMinUsec;
899 }
900 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000901}
902
903error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700904 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000905 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700906 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700907 int32_t aidlHwAvSync;
908 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
909 return VALUE_OR_RETURN_STATUS(
910 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +0000911}
912
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000913status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
914 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700915 if (mModule == nullptr) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000916 return mModule->dump(fd, Args(args).args(), args.size());
David Li9cf5e622023-03-21 00:51:10 +0800917}
Shunkai Yao51202502022-12-12 06:11:46 +0000918
Eric Laurent7af6ee72023-06-29 11:44:54 +0200919status_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700920 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000921 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700922 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700923 if (supports == nullptr) {
924 return BAD_VALUE;
925 }
926 return statusTFromBinderStatus(mModule->supportsVariableLatency(supports));
Shunkai Yao51202502022-12-12 06:11:46 +0000927}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000928
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100929status_t DeviceHalAidl::getSoundDoseInterface(const std::string& module,
930 ::ndk::SpAIBinder* soundDoseBinder) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700931 if (soundDoseBinder == nullptr) {
932 return BAD_VALUE;
933 }
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100934 if (mSoundDose == nullptr) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700935 ALOGE("%s failed to retrieve the sound dose interface for module %s",
936 __func__, module.c_str());
937 return BAD_VALUE;
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100938 }
Vlad Popae1f33902023-10-30 19:48:25 -0700939
940 if (mSoundDose == nullptr) {
941 ALOGE("%s failed to return the sound dose interface for module %s: not implemented",
942 __func__,
943 module.c_str());
944 return NO_INIT;
945 }
946
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100947 *soundDoseBinder = mSoundDose->asBinder();
948 ALOGI("%s using audio AIDL HAL sound dose interface", __func__);
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100949 return OK;
950}
jiabin872de702023-04-27 22:04:31 +0000951
952status_t DeviceHalAidl::prepareToDisconnectExternalDevice(const struct audio_port_v7* port) {
jiabin62750c22023-12-21 22:06:07 +0000953 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
954 TIME_CHECK();
955 if (mModule == nullptr) return NO_INIT;
956 if (port == nullptr) {
957 return BAD_VALUE;
958 }
959 const bool isInput = VALUE_OR_RETURN_STATUS(
960 ::aidl::android::portDirection(port->role, port->type)) ==
961 ::aidl::android::AudioPortDirection::INPUT;
962 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
963 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
964 if (aidlPort.ext.getTag() != AudioPortExt::device) {
965 ALOGE("%s: provided port is not a device port (module %s): %s",
966 __func__, mInstance.c_str(), aidlPort.toString().c_str());
967 return BAD_VALUE;
968 }
969 status_t status = NO_ERROR;
970 {
971 std::lock_guard l(mLock);
972 status = mMapper.prepareToDisconnectExternalDevice(aidlPort);
973 }
974 if (status == UNKNOWN_TRANSACTION) {
975 // If there is not AIDL API defined for `prepareToDisconnectExternalDevice`.
976 // Call `setConnectedState` instead.
977 RETURN_STATUS_IF_ERROR(setConnectedState(port, false /*connected*/));
978 std::lock_guard l(mLock);
979 mDeviceDisconnectionNotified.insert(port->id);
980 // Return that there was no error as otherwise the disconnection procedure will not be
981 // considered complete for upper layers, and 'setConnectedState' will not be called again
982 return OK;
983 } else {
984 return status;
985 }
jiabin872de702023-04-27 22:04:31 +0000986}
987
Mikhail Naganove93a0862023-03-15 17:06:59 -0700988status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
Mikhail Naganovae9063d2023-11-07 16:43:51 -0800989 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700990 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700991 if (mModule == nullptr) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700992 if (port == nullptr) {
993 return BAD_VALUE;
994 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700995 if (!connected) {
996 std::lock_guard l(mLock);
997 if (mDeviceDisconnectionNotified.erase(port->id) > 0) {
998 // For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
jiabin62750c22023-12-21 22:06:07 +0000999 // and then call `setConnectedState`. If `prepareToDisconnectExternalDevice` doesn't
1000 // exit, `setConnectedState` will be called when calling
1001 // `prepareToDisconnectExternalDevice`. Do not call to the HAL if previous call is
1002 // successful. Also remove the cache here to avoid a large cache after a long run.
Mikhail Naganovac9d4e72023-10-23 12:00:09 -07001003 return OK;
1004 }
jiabin872de702023-04-27 22:04:31 +00001005 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001006 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
1007 ::aidl::android::AudioPortDirection::INPUT;
1008 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
1009 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
1010 if (aidlPort.ext.getTag() != AudioPortExt::device) {
1011 ALOGE("%s: provided port is not a device port (module %s): %s",
1012 __func__, mInstance.c_str(), aidlPort.toString().c_str());
1013 return BAD_VALUE;
1014 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -07001015 std::lock_guard l(mLock);
1016 return mMapper.setDevicePortConnectedState(aidlPort, connected);
Mikhail Naganove93a0862023-03-15 17:06:59 -07001017}
1018
1019status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
1020 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -07001021 if (mModule == nullptr) return NO_INIT;
1022 {
1023 std::lock_guard l(mLock);
Mikhail Naganov6b5da722024-03-14 12:59:32 -07001024 mMapper.resetUnusedPatchesAndPortConfigs();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -07001025 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001026 ModuleDebug debug{ .simulateDeviceConnections = enabled };
1027 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
1028 // This is important to log as it affects HAL behavior.
1029 if (status == OK) {
1030 ALOGI("%s: set enabled: %d", __func__, enabled);
1031 } else {
1032 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
1033 }
1034 return status;
1035}
1036
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001037status_t DeviceHalAidl::filterAndRetrieveBtA2dpParameters(
1038 AudioParameter &keys, AudioParameter *result) {
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001039 if (String8 key = String8(AudioParameter::keyReconfigA2dpSupported); keys.containsKey(key)) {
1040 keys.remove(key);
David Lia7761ed2023-11-03 17:22:07 +00001041 if (mBluetoothA2dp != nullptr) {
1042 bool supports;
1043 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1044 mBluetoothA2dp->supportsOffloadReconfiguration(&supports)));
1045 result->addInt(key, supports ? 1 : 0);
1046 } else {
1047 ALOGI("%s: no IBluetoothA2dp on %s", __func__, mInstance.c_str());
1048 result->addInt(key, 0);
1049 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001050 }
1051 return OK;
1052}
1053
Eric Laurent7e3c0832023-11-30 15:04:50 +01001054status_t DeviceHalAidl::filterAndRetrieveBtLeParameters(
1055 AudioParameter &keys, AudioParameter *result) {
1056 if (String8 key = String8(AudioParameter::keyReconfigLeSupported); keys.containsKey(key)) {
1057 keys.remove(key);
1058 if (mBluetoothLe != nullptr) {
1059 bool supports;
1060 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1061 mBluetoothLe->supportsOffloadReconfiguration(&supports)));
1062 result->addInt(key, supports ? 1 : 0);
1063 } else {
1064 ALOGI("%s: no mBluetoothLe on %s", __func__, mInstance.c_str());
1065 result->addInt(key, 0);
1066 }
1067 }
1068 return OK;
1069}
1070
Mikhail Naganovccc82112023-04-27 18:14:15 -07001071status_t DeviceHalAidl::filterAndUpdateBtA2dpParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001072 std::optional<bool> a2dpEnabled;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001073 std::optional<std::vector<VendorParameter>> reconfigureOffload;
Mikhail Naganovccc82112023-04-27 18:14:15 -07001074 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1075 parameters, String8(AudioParameter::keyBtA2dpSuspended),
1076 [&a2dpEnabled](const String8& trueOrFalse) {
1077 if (trueOrFalse == AudioParameter::valueTrue) {
1078 a2dpEnabled = false; // 'suspended' == true
1079 return OK;
1080 } else if (trueOrFalse == AudioParameter::valueFalse) {
1081 a2dpEnabled = true; // 'suspended' == false
1082 return OK;
1083 }
1084 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1085 AudioParameter::keyBtA2dpSuspended, trueOrFalse.c_str());
1086 return BAD_VALUE;
1087 }));
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001088 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1089 parameters, String8(AudioParameter::keyReconfigA2dp),
1090 [&](const String8& value) -> status_t {
Mikhail Naganove5011002024-01-26 10:57:19 -08001091 std::vector<VendorParameter> result;
1092 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1093 mVendorExt->parseBluetoothA2dpReconfigureOffload(
1094 std::string(value.c_str()), &result)));
1095 reconfigureOffload = std::move(result);
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001096 return OK;
1097 }));
Mikhail Naganovccc82112023-04-27 18:14:15 -07001098 if (mBluetoothA2dp != nullptr && a2dpEnabled.has_value()) {
1099 return statusTFromBinderStatus(mBluetoothA2dp->setEnabled(a2dpEnabled.value()));
1100 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001101 if (mBluetoothA2dp != nullptr && reconfigureOffload.has_value()) {
1102 return statusTFromBinderStatus(mBluetoothA2dp->reconfigureOffload(
1103 reconfigureOffload.value()));
1104 }
Mikhail Naganovccc82112023-04-27 18:14:15 -07001105 return OK;
1106}
1107
1108status_t DeviceHalAidl::filterAndUpdateBtHfpParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001109 IBluetooth::HfpConfig hfpConfig;
1110 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1111 parameters, String8(AudioParameter::keyBtHfpEnable),
1112 [&hfpConfig](const String8& trueOrFalse) {
1113 if (trueOrFalse == AudioParameter::valueTrue) {
1114 hfpConfig.isEnabled = Boolean{ .value = true };
1115 return OK;
1116 } else if (trueOrFalse == AudioParameter::valueFalse) {
1117 hfpConfig.isEnabled = Boolean{ .value = false };
1118 return OK;
1119 }
1120 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1121 AudioParameter::keyBtHfpEnable, trueOrFalse.c_str());
1122 return BAD_VALUE;
1123 }));
1124 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1125 parameters, String8(AudioParameter::keyBtHfpSamplingRate),
1126 [&hfpConfig](int sampleRate) {
1127 return sampleRate > 0 ?
1128 hfpConfig.sampleRate = Int{ .value = sampleRate }, OK : BAD_VALUE;
1129 }));
1130 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1131 parameters, String8(AudioParameter::keyBtHfpVolume),
1132 [&hfpConfig](int volume0to15) {
1133 if (volume0to15 >= 0 && volume0to15 <= 15) {
1134 hfpConfig.volume = Float{ .value = volume0to15 / 15.0f };
1135 return OK;
1136 }
1137 return BAD_VALUE;
1138 }));
1139 if (mBluetooth != nullptr && hfpConfig != IBluetooth::HfpConfig{}) {
1140 IBluetooth::HfpConfig newHfpConfig;
1141 return statusTFromBinderStatus(mBluetooth->setHfpConfig(hfpConfig, &newHfpConfig));
1142 }
1143 return OK;
1144}
1145
1146status_t DeviceHalAidl::filterAndUpdateBtLeParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001147 std::optional<bool> leEnabled;
Eric Laurent7e3c0832023-11-30 15:04:50 +01001148 std::optional<std::vector<VendorParameter>> reconfigureOffload;
Mikhail Naganovccc82112023-04-27 18:14:15 -07001149 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1150 parameters, String8(AudioParameter::keyBtLeSuspended),
1151 [&leEnabled](const String8& trueOrFalse) {
1152 if (trueOrFalse == AudioParameter::valueTrue) {
1153 leEnabled = false; // 'suspended' == true
1154 return OK;
1155 } else if (trueOrFalse == AudioParameter::valueFalse) {
1156 leEnabled = true; // 'suspended' == false
1157 return OK;
1158 }
1159 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1160 AudioParameter::keyBtLeSuspended, trueOrFalse.c_str());
1161 return BAD_VALUE;
1162 }));
Eric Laurent7e3c0832023-11-30 15:04:50 +01001163 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1164 parameters, String8(AudioParameter::keyReconfigLe),
1165 [&](const String8& value) -> status_t {
1166 if (mVendorExt != nullptr) {
1167 std::vector<VendorParameter> result;
1168 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1169 mVendorExt->parseBluetoothLeReconfigureOffload(
1170 std::string(value.c_str()), &result)));
1171 reconfigureOffload = std::move(result);
1172 } else {
1173 reconfigureOffload = std::vector<VendorParameter>();
1174 }
1175 return OK;
1176 }));
Mikhail Naganovccc82112023-04-27 18:14:15 -07001177 if (mBluetoothLe != nullptr && leEnabled.has_value()) {
1178 return statusTFromBinderStatus(mBluetoothLe->setEnabled(leEnabled.value()));
1179 }
Eric Laurent7e3c0832023-11-30 15:04:50 +01001180 if (mBluetoothLe != nullptr && reconfigureOffload.has_value()) {
1181 return statusTFromBinderStatus(mBluetoothLe->reconfigureOffload(
1182 reconfigureOffload.value()));
1183 }
Mikhail Naganovccc82112023-04-27 18:14:15 -07001184 return OK;
1185}
1186
1187status_t DeviceHalAidl::filterAndUpdateBtScoParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001188 IBluetooth::ScoConfig scoConfig;
1189 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1190 parameters, String8(AudioParameter::keyBtSco),
1191 [&scoConfig](const String8& onOrOff) {
1192 if (onOrOff == AudioParameter::valueOn) {
1193 scoConfig.isEnabled = Boolean{ .value = true };
1194 return OK;
1195 } else if (onOrOff == AudioParameter::valueOff) {
1196 scoConfig.isEnabled = Boolean{ .value = false };
1197 return OK;
1198 }
1199 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1200 AudioParameter::keyBtSco, onOrOff.c_str());
1201 return BAD_VALUE;
1202 }));
1203 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1204 parameters, String8(AudioParameter::keyBtScoHeadsetName),
1205 [&scoConfig](const String8& name) {
1206 scoConfig.debugName = name;
1207 return OK;
1208 }));
1209 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1210 parameters, String8(AudioParameter::keyBtNrec),
1211 [&scoConfig](const String8& onOrOff) {
1212 if (onOrOff == AudioParameter::valueOn) {
1213 scoConfig.isNrecEnabled = Boolean{ .value = true };
1214 return OK;
1215 } else if (onOrOff == AudioParameter::valueOff) {
1216 scoConfig.isNrecEnabled = Boolean{ .value = false };
1217 return OK;
1218 }
1219 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1220 AudioParameter::keyBtNrec, onOrOff.c_str());
1221 return BAD_VALUE;
1222 }));
1223 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1224 parameters, String8(AudioParameter::keyBtScoWb),
1225 [&scoConfig](const String8& onOrOff) {
1226 if (onOrOff == AudioParameter::valueOn) {
1227 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO_WB;
1228 return OK;
1229 } else if (onOrOff == AudioParameter::valueOff) {
1230 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO;
1231 return OK;
1232 }
1233 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1234 AudioParameter::keyBtScoWb, onOrOff.c_str());
1235 return BAD_VALUE;
1236 }));
1237 if (mBluetooth != nullptr && scoConfig != IBluetooth::ScoConfig{}) {
1238 IBluetooth::ScoConfig newScoConfig;
1239 return statusTFromBinderStatus(mBluetooth->setScoConfig(scoConfig, &newScoConfig));
1240 }
1241 return OK;
1242}
1243
Mikhail Naganove92c34b2023-05-31 14:24:48 -07001244status_t DeviceHalAidl::filterAndUpdateScreenParameters(AudioParameter &parameters) {
Mikhail Naganove92c34b2023-05-31 14:24:48 -07001245 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1246 parameters, String8(AudioParameter::keyScreenState),
1247 [&](const String8& onOrOff) -> status_t {
1248 std::optional<bool> isTurnedOn;
1249 if (onOrOff == AudioParameter::valueOn) {
1250 isTurnedOn = true;
1251 } else if (onOrOff == AudioParameter::valueOff) {
1252 isTurnedOn = false;
1253 }
1254 if (!isTurnedOn.has_value()) {
1255 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1256 AudioParameter::keyScreenState, onOrOff.c_str());
1257 return BAD_VALUE;
1258 }
1259 return statusTFromBinderStatus(
1260 mModule->updateScreenState(isTurnedOn.value()));
1261 }));
1262 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1263 parameters, String8(AudioParameter::keyScreenRotation),
1264 [&](int rotationDegrees) -> status_t {
1265 IModule::ScreenRotation rotation;
1266 switch (rotationDegrees) {
1267 case 0: rotation = IModule::ScreenRotation::DEG_0; break;
1268 case 90: rotation = IModule::ScreenRotation::DEG_90; break;
1269 case 180: rotation = IModule::ScreenRotation::DEG_180; break;
1270 case 270: rotation = IModule::ScreenRotation::DEG_270; break;
1271 default:
1272 ALOGE("setParameters: parameter key \"%s\" has invalid value %d",
1273 AudioParameter::keyScreenRotation, rotationDegrees);
1274 return BAD_VALUE;
1275 }
1276 return statusTFromBinderStatus(mModule->updateScreenRotation(rotation));
1277 }));
1278 return OK;
1279}
1280
Mikhail Naganovb9a81312023-07-18 13:55:34 -07001281status_t DeviceHalAidl::filterAndUpdateTelephonyParameters(AudioParameter &parameters) {
Mikhail Naganovb9a81312023-07-18 13:55:34 -07001282 using TtyMode = ITelephony::TelecomConfig::TtyMode;
1283 ITelephony::TelecomConfig telConfig;
1284 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1285 parameters, String8(AudioParameter::keyTtyMode),
1286 [&telConfig](const String8& mode) {
1287 if (mode == AudioParameter::valueTtyModeOff) {
1288 telConfig.ttyMode = TtyMode::OFF;
1289 return OK;
1290 } else if (mode == AudioParameter::valueTtyModeFull) {
1291 telConfig.ttyMode = TtyMode::FULL;
1292 return OK;
1293 } else if (mode == AudioParameter::valueTtyModeHco) {
1294 telConfig.ttyMode = TtyMode::HCO;
1295 return OK;
1296 } else if (mode == AudioParameter::valueTtyModeVco) {
1297 telConfig.ttyMode = TtyMode::VCO;
1298 return OK;
1299 }
1300 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1301 AudioParameter::keyTtyMode, mode.c_str());
1302 return BAD_VALUE;
1303 }));
1304 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1305 parameters, String8(AudioParameter::keyHacSetting),
1306 [&telConfig](const String8& onOrOff) {
1307 if (onOrOff == AudioParameter::valueHacOn) {
1308 telConfig.isHacEnabled = Boolean{ .value = true };
1309 return OK;
1310 } else if (onOrOff == AudioParameter::valueHacOff) {
1311 telConfig.isHacEnabled = Boolean{ .value = false };
1312 return OK;
1313 }
1314 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1315 AudioParameter::keyHacSetting, onOrOff.c_str());
1316 return BAD_VALUE;
1317 }));
1318 if (mTelephony != nullptr && telConfig != ITelephony::TelecomConfig{}) {
1319 ITelephony::TelecomConfig newTelConfig;
1320 return statusTFromBinderStatus(
1321 mTelephony->setTelecomConfig(telConfig, &newTelConfig));
1322 }
1323 return OK;
1324}
1325
Mikhail Naganovdfd594e2023-02-08 16:59:41 -08001326void DeviceHalAidl::clearCallbacks(void* cookie) {
1327 std::lock_guard l(mLock);
1328 mCallbacks.erase(cookie);
1329}
1330
1331sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1332 return getCallbackImpl(cookie, &Callbacks::out);
1333}
1334
1335void DeviceHalAidl::setStreamOutCallback(
1336 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1337 setCallbackImpl(cookie, &Callbacks::out, cb);
1338}
1339
1340sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1341 void* cookie) {
1342 return getCallbackImpl(cookie, &Callbacks::event);
1343}
1344
1345void DeviceHalAidl::setStreamOutEventCallback(
1346 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1347 setCallbackImpl(cookie, &Callbacks::event, cb);
1348}
1349
1350sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1351 void* cookie) {
1352 return getCallbackImpl(cookie, &Callbacks::latency);
1353}
1354
1355void DeviceHalAidl::setStreamOutLatencyModeCallback(
1356 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1357 setCallbackImpl(cookie, &Callbacks::latency, cb);
1358}
1359
1360template<class C>
1361sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1362 std::lock_guard l(mLock);
1363 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1364 return ((it->second).*field).promote();
1365 }
1366 return nullptr;
1367}
1368template<class C>
1369void DeviceHalAidl::setCallbackImpl(
1370 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1371 std::lock_guard l(mLock);
1372 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1373 (it->second).*field = cb;
1374 }
1375}
1376
Mikhail Naganov31d46652023-01-10 18:29:25 +00001377} // namespace android