blob: 86dd66361fddf98be9ab0136fcc7e7f4f353cffa [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 {
Mikhail Naganovf548cd32024-05-29 17:06:46 +0000389 return runCb([](CbRef cb) { cb->onError(true /*isHardError*/); });
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800390 }
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);
Kuowei Li3b9a69d2024-06-07 17:54:32 +0800462 const bool isHwAvSync = isBitPositionFlagSet(
463 aidlOutputFlags, AudioOutputFlags::HW_AV_SYNC);
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800464 std::shared_ptr<OutputStreamCallbackAidl> streamCb;
465 if (isOffload) {
466 streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
467 }
468 auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
Kuowei Li3b9a69d2024-06-07 17:54:32 +0800469 if (isOffload || isHwAvSync) {
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800470 args.offloadInfo = aidlConfig.offloadInfo;
Kuowei Li3b9a69d2024-06-07 17:54:32 +0800471 }
472 if (isOffload) {
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800473 args.callback = streamCb;
474 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800475 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800476 args.eventCallback = eventCb;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800477 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
478 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800479 StreamContextAidl context(ret.desc, isOffload);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800480 if (!context.isValid()) {
481 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
482 __func__, ret.desc.toString().c_str());
483 return NO_INIT;
484 }
Mikhail Naganov23224a12024-03-28 02:15:21 +0000485 auto stream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700486 std::move(ret.stream), mVendorExt, this /*callbackBroker*/);
Mikhail Naganov23224a12024-03-28 02:15:21 +0000487 *outStream = stream;
488 /* StreamOutHalInterface* */ void* cbCookie = (*outStream).get();
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800489 {
490 std::lock_guard l(mLock);
491 mCallbacks.emplace(cbCookie, Callbacks{});
Mikhail Naganov78f7f9a2023-11-16 15:49:23 -0800492 mMapper.addStream(*outStream, mixPortConfig.id, aidlPatch.id);
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800493 }
Mikhail Naganov23224a12024-03-28 02:15:21 +0000494 if (streamCb) {
495 streamCb->setCookie(cbCookie);
496 // Although StreamOutHalAidl implements StreamOutHalInterfaceCallback,
497 // we always go via the CallbackBroker for consistency.
498 setStreamOutCallback(cbCookie, stream);
499 }
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800500 eventCb->setCookie(cbCookie);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800501 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000502 return OK;
503}
504
Mikhail Naganov31d46652023-01-10 18:29:25 +0000505status_t DeviceHalAidl::openInputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800506 audio_io_handle_t handle, audio_devices_t devices,
507 struct audio_config* config, audio_input_flags_t flags,
508 const char* address, audio_source_t source,
509 audio_devices_t outputDevice, const char* outputDeviceAddress,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000510 sp<StreamInHalInterface>* inStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800511 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700512 TIME_CHECK();
513 if (mModule == nullptr) return NO_INIT;
514 if (inStream == nullptr || config == nullptr) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000515 return BAD_VALUE;
516 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700517 constexpr bool isInput = true;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800518 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
519 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
520 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700521 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, isInput));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800522 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
523 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
524 int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
525 ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
526 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
527 AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
528 ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
529 AudioPortConfig mixPortConfig;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700530 AudioPatch aidlPatch;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700531 Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
532 {
533 std::lock_guard l(mLock);
534 RETURN_STATUS_IF_ERROR(mMapper.prepareToOpenStream(
535 aidlHandle, aidlDevice, aidlFlags, aidlSource,
536 &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
537 }
538 *config = VALUE_OR_RETURN_STATUS(
539 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(aidlConfig, isInput));
Mikhail Naganovca92a5c2023-12-07 14:00:48 -0800540 if (mixPortConfig.id == 0) return BAD_VALUE; // HAL suggests a different config.
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800541 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
542 args.portConfigId = mixPortConfig.id;
543 RecordTrackMetadata aidlTrackMetadata{
544 .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
545 if (outputDevice != AUDIO_DEVICE_NONE) {
546 aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
547 ::aidl::android::legacy2aidl_audio_device_AudioDevice(
548 outputDevice, outputDeviceAddress));
549 }
550 args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
551 args.bufferSizeFrames = aidlConfig.frameCount;
552 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
553 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800554 StreamContextAidl context(ret.desc, false /*isAsynchronous*/);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800555 if (!context.isValid()) {
556 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
557 __func__, ret.desc.toString().c_str());
558 return NO_INIT;
559 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700560 *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700561 std::move(ret.stream), mVendorExt, this /*micInfoProvider*/);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700562 {
563 std::lock_guard l(mLock);
Mikhail Naganov78f7f9a2023-11-16 15:49:23 -0800564 mMapper.addStream(*inStream, mixPortConfig.id, aidlPatch.id);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700565 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800566 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000567 return OK;
568}
569
570status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700571 if (supportsPatches == nullptr) {
572 return BAD_VALUE;
573 }
Shunkai Yao51202502022-12-12 06:11:46 +0000574 *supportsPatches = true;
575 return OK;
576}
577
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800578status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
579 const struct audio_port_config* sources,
580 unsigned int num_sinks,
581 const struct audio_port_config* sinks,
582 audio_patch_handle_t* patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800583 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000584 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700585 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800586 if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
587 sources == nullptr || sinks == nullptr || patch == nullptr) {
588 return BAD_VALUE;
589 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800590 // When the patch handle (*patch) is AUDIO_PATCH_HANDLE_NONE, it means
591 // the framework wants to create a new patch. The handle has to be generated
592 // by the HAL. Since handles generated this way can only be unique within
593 // a HAL module, the framework generates a globally unique handle, and maps
594 // it on the <HAL module, patch handle> pair.
595 // When the patch handle is set, it meant the framework intends to update
596 // an existing patch.
597 //
598 // This behavior corresponds to HAL module behavior, with the only difference
599 // that the HAL module uses `int32_t` for patch IDs. The following assert ensures
600 // that both the framework and the HAL use the same value for "no ID":
601 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800602
603 // Upon conversion, mix port configs contain audio configuration, while
604 // device port configs contain device address. This data is used to find
605 // or create HAL configs.
606 std::vector<AudioPortConfig> aidlSources, aidlSinks;
607 for (unsigned int i = 0; i < num_sources; ++i) {
608 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
609 sources[i].role, sources[i].type)) ==
610 ::aidl::android::AudioPortDirection::INPUT;
611 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
612 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
613 sources[i], isInput, 0)));
614 }
615 for (unsigned int i = 0; i < num_sinks; ++i) {
616 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
617 sinks[i].role, sinks[i].type)) ==
618 ::aidl::android::AudioPortDirection::INPUT;
619 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
620 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
621 sinks[i], isInput, 0)));
622 }
Mikhail Naganova317a802024-03-15 18:03:10 +0000623 int32_t aidlPatchId = static_cast<int32_t>(*patch);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700624 Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
625 {
626 std::lock_guard l(mLock);
Mikhail Naganova317a802024-03-15 18:03:10 +0000627 // Check for patches that only exist for the framework, or have different HAL patch ID.
628 if (int32_t aidlHalPatchId = mMapper.findFwkPatch(aidlPatchId); aidlHalPatchId != 0) {
629 if (aidlHalPatchId == aidlPatchId) {
630 // This patch was previously released by the HAL. Thus we need to pass '0'
631 // to the HAL to obtain a new patch.
632 int32_t newAidlPatchId = 0;
633 RETURN_STATUS_IF_ERROR(mMapper.createOrUpdatePatch(
634 aidlSources, aidlSinks, &newAidlPatchId, &cleanups));
635 mMapper.updateFwkPatch(aidlPatchId, newAidlPatchId);
636 } else {
637 RETURN_STATUS_IF_ERROR(mMapper.createOrUpdatePatch(
638 aidlSources, aidlSinks, &aidlHalPatchId, &cleanups));
639 }
640 } else {
641 RETURN_STATUS_IF_ERROR(mMapper.createOrUpdatePatch(
642 aidlSources, aidlSinks, &aidlPatchId, &cleanups));
643 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800644 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700645 *patch = static_cast<audio_patch_handle_t>(aidlPatchId);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800646 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000647 return OK;
648}
649
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800650status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800651 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000652 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700653 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800654 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
655 if (patch == AUDIO_PATCH_HANDLE_NONE) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800656 return BAD_VALUE;
657 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700658 std::lock_guard l(mLock);
Mikhail Naganova317a802024-03-15 18:03:10 +0000659 // Check for patches that only exist for the framework, or have different HAL patch ID.
660 int32_t aidlPatchId = static_cast<int32_t>(patch);
661 if (int32_t aidlHalPatchId = mMapper.findFwkPatch(aidlPatchId); aidlHalPatchId != 0) {
662 if (aidlHalPatchId == aidlPatchId) {
663 // This patch was previously released by the HAL, just need to finish its removal.
664 mMapper.eraseFwkPatch(aidlPatchId);
665 return OK;
666 } else {
667 // This patch has a HAL patch ID which is different
668 aidlPatchId = aidlHalPatchId;
669 }
670 }
671 RETURN_STATUS_IF_ERROR(mMapper.releaseAudioPatch(aidlPatchId));
Shunkai Yao51202502022-12-12 06:11:46 +0000672 return OK;
673}
674
Mikhail Naganove93a0862023-03-15 17:06:59 -0700675status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700676 if (port == nullptr) {
677 return BAD_VALUE;
678 }
679 audio_port_v7 portV7;
680 audio_populate_audio_port_v7(port, &portV7);
681 RETURN_STATUS_IF_ERROR(getAudioPort(&portV7));
682 return audio_populate_audio_port(&portV7, port) ? OK : BAD_VALUE;
683}
684
685status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
686 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
687 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700688 if (mModule == nullptr) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700689 if (port == nullptr) {
690 return BAD_VALUE;
691 }
692 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
693 ::aidl::android::AudioPortDirection::INPUT;
694 auto aidlPort = VALUE_OR_RETURN_STATUS(
695 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
696 if (aidlPort.ext.getTag() != AudioPortExt::device) {
697 ALOGE("%s: provided port is not a device port (module %s): %s",
698 __func__, mInstance.c_str(), aidlPort.toString().c_str());
699 return BAD_VALUE;
700 }
701 const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
702 // It seems that we don't have to call HAL since all valid ports have been added either
703 // during initialization, or while handling connection of an external device.
Mikhail Naganove93a0862023-03-15 17:06:59 -0700704 const int32_t fwkId = aidlPort.id;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700705 {
706 std::lock_guard l(mLock);
707 RETURN_STATUS_IF_ERROR(mMapper.getAudioPortCached(matchDevice, &aidlPort));
708 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700709 aidlPort.id = fwkId;
710 *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
711 aidlPort, isInput));
712 return OK;
713}
714
jiabin12537fc2023-10-12 17:56:08 +0000715status_t DeviceHalAidl::getAudioMixPort(const struct audio_port_v7 *devicePort,
716 struct audio_port_v7 *mixPort) {
717 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700718 TIME_CHECK();
719 if (mModule == nullptr) return NO_INIT;
720 if (devicePort == nullptr || mixPort == nullptr ||
721 devicePort->type != AUDIO_PORT_TYPE_DEVICE || mixPort->type != AUDIO_PORT_TYPE_MIX) {
jiabin12537fc2023-10-12 17:56:08 +0000722 return BAD_VALUE;
723 }
724 const int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
725 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(mixPort->ext.mix.handle));
jiabin12537fc2023-10-12 17:56:08 +0000726 AudioPort port;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700727 {
728 std::lock_guard l(mLock);
729 RETURN_STATUS_IF_ERROR(mMapper.getAudioMixPort(aidlHandle, &port));
jiabin12537fc2023-10-12 17:56:08 +0000730 }
731 const bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
732 mixPort->role, mixPort->type)) == ::aidl::android::AudioPortDirection::INPUT;
733 *mixPort = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
734 port, isInput));
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700735 return OK;
jiabin12537fc2023-10-12 17:56:08 +0000736}
737
Mikhail Naganove93a0862023-03-15 17:06:59 -0700738status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
739 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
740 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700741 if (mModule == nullptr) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700742 if (config == nullptr) {
743 return BAD_VALUE;
744 }
745 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
746 config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
747 AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
748 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
749 *config, isInput, 0 /*portId*/));
750 AudioPortConfig portConfig;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700751 std::lock_guard l(mLock);
Mikhail Naganovca92a5c2023-12-07 14:00:48 -0800752 return mMapper.setPortConfig(requestedPortConfig, std::set<int32_t>(), &portConfig);
Shunkai Yao51202502022-12-12 06:11:46 +0000753}
754
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800755MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700756 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
757 TIME_CHECK();
758 if (!mModule) return {};
759 std::lock_guard l(mLock);
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800760 if (mMicrophones.status == Microphones::Status::UNKNOWN) {
761 TIME_CHECK();
762 std::vector<MicrophoneInfo> aidlInfo;
763 status_t status = statusTFromBinderStatus(mModule->getMicrophones(&aidlInfo));
764 if (status == OK) {
765 mMicrophones.status = Microphones::Status::QUERIED;
766 mMicrophones.info = std::move(aidlInfo);
767 } else if (status == INVALID_OPERATION) {
768 mMicrophones.status = Microphones::Status::NOT_SUPPORTED;
769 } else {
770 ALOGE("%s: Unexpected status from 'IModule.getMicrophones': %d", __func__, status);
771 return {};
772 }
773 }
774 if (mMicrophones.status == Microphones::Status::QUERIED) {
775 return &mMicrophones.info;
776 }
777 return {}; // NOT_SUPPORTED
778}
779
Shunkai Yao51202502022-12-12 06:11:46 +0000780status_t DeviceHalAidl::getMicrophones(
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800781 std::vector<audio_microphone_characteristic_t>* microphones) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700782 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
783 TIME_CHECK();
784 if (mModule == nullptr) return NO_INIT;
785 if (microphones == nullptr) {
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800786 return BAD_VALUE;
787 }
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800788 auto staticInfo = getMicrophoneInfo();
789 if (!staticInfo) return INVALID_OPERATION;
790 std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
791 emptyDynamicInfo.reserve(staticInfo->size());
792 std::transform(staticInfo->begin(), staticInfo->end(), std::back_inserter(emptyDynamicInfo),
793 [](const auto& info) { return MicrophoneDynamicInfo{ .id = info.id }; });
794 *microphones = VALUE_OR_RETURN_STATUS(
795 ::aidl::android::convertContainers<std::vector<audio_microphone_characteristic_t>>(
796 *staticInfo, emptyDynamicInfo,
797 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t)
798 );
Shunkai Yao51202502022-12-12 06:11:46 +0000799 return OK;
800}
801
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700802status_t DeviceHalAidl::addDeviceEffect(
803 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700804 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700805 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700806 if (mModule == nullptr) return NO_INIT;
807 if (device == nullptr || effect == nullptr) {
Shunkai Yao51202502022-12-12 06:11:46 +0000808 return BAD_VALUE;
809 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700810 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
811 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
812 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
813 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
814 *device, isInput, 0));
815 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
816 ALOGE("%s: provided port config is not a device port config: %s",
817 __func__, requestedPortConfig.toString().c_str());
818 return BAD_VALUE;
819 }
820 AudioPortConfig devicePortConfig;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700821 Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
822 {
823 std::lock_guard l(mLock);
Mikhail Naganovca92a5c2023-12-07 14:00:48 -0800824 RETURN_STATUS_IF_ERROR(mMapper.setPortConfig(
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700825 requestedPortConfig, {} /*destinationPortIds*/, &devicePortConfig, &cleanups));
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700826 }
827 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
828 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->addDeviceEffect(
829 devicePortConfig.id, aidlEffect->getIEffect())));
830 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000831 return OK;
832}
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700833status_t DeviceHalAidl::removeDeviceEffect(
834 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700835 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700836 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700837 if (mModule == nullptr) return NO_INIT;
838 if (device == nullptr || effect == nullptr) {
Shunkai Yao51202502022-12-12 06:11:46 +0000839 return BAD_VALUE;
840 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700841 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
842 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
843 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
844 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
845 *device, isInput, 0));
846 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
847 ALOGE("%s: provided port config is not a device port config: %s",
848 __func__, requestedPortConfig.toString().c_str());
849 return BAD_VALUE;
850 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700851 AudioPortConfig devicePortConfig;
852 {
853 std::lock_guard l(mLock);
854 RETURN_STATUS_IF_ERROR(mMapper.findPortConfig(
855 requestedPortConfig.ext.get<AudioPortExt::Tag::device>().device,
856 &devicePortConfig));
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700857 }
858 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
859 return statusTFromBinderStatus(mModule->removeDeviceEffect(
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700860 devicePortConfig.id, aidlEffect->getIEffect()));
Shunkai Yao51202502022-12-12 06:11:46 +0000861}
862
863status_t DeviceHalAidl::getMmapPolicyInfos(
David Li9cf5e622023-03-21 00:51:10 +0800864 media::audio::common::AudioMMapPolicyType policyType,
865 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700866 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000867 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700868 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov25bc9a22023-04-21 18:48:16 -0700869 AudioMMapPolicyType mmapPolicyType = VALUE_OR_RETURN_STATUS(
870 cpp2ndk_AudioMMapPolicyType(policyType));
David Li9cf5e622023-03-21 00:51:10 +0800871
872 std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
873
874 if (status_t status = statusTFromBinderStatus(
875 mModule->getMmapPolicyInfos(mmapPolicyType, &mmapPolicyInfos)); status != OK) {
876 return status;
877 }
878
879 *policyInfos = VALUE_OR_RETURN_STATUS(
880 convertContainer<std::vector<media::audio::common::AudioMMapPolicyInfo>>(
881 mmapPolicyInfos, ndk2cpp_AudioMMapPolicyInfo));
Shunkai Yao51202502022-12-12 06:11:46 +0000882 return OK;
883}
884
885int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700886 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000887 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700888 if (mModule == nullptr) return NO_INIT;
David Li9cf5e622023-03-21 00:51:10 +0800889 int32_t mixerBurstCount = 0;
890 if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
891 return mixerBurstCount;
892 }
893 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000894}
895
896int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700897 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000898 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700899 if (mModule == nullptr) return NO_INIT;
David Li9cf5e622023-03-21 00:51:10 +0800900 int32_t hardwareBurstMinUsec = 0;
901 if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
902 return hardwareBurstMinUsec;
903 }
904 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000905}
906
907error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700908 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000909 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700910 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700911 int32_t aidlHwAvSync;
912 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
913 return VALUE_OR_RETURN_STATUS(
914 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +0000915}
916
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000917status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
918 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700919 if (mModule == nullptr) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000920 return mModule->dump(fd, Args(args).args(), args.size());
David Li9cf5e622023-03-21 00:51:10 +0800921}
Shunkai Yao51202502022-12-12 06:11:46 +0000922
Eric Laurent7af6ee72023-06-29 11:44:54 +0200923status_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700924 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000925 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700926 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700927 if (supports == nullptr) {
928 return BAD_VALUE;
929 }
930 return statusTFromBinderStatus(mModule->supportsVariableLatency(supports));
Shunkai Yao51202502022-12-12 06:11:46 +0000931}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000932
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100933status_t DeviceHalAidl::getSoundDoseInterface(const std::string& module,
934 ::ndk::SpAIBinder* soundDoseBinder) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700935 if (soundDoseBinder == nullptr) {
936 return BAD_VALUE;
937 }
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100938 if (mSoundDose == nullptr) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700939 ALOGE("%s failed to retrieve the sound dose interface for module %s",
940 __func__, module.c_str());
941 return BAD_VALUE;
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100942 }
Vlad Popae1f33902023-10-30 19:48:25 -0700943
944 if (mSoundDose == nullptr) {
945 ALOGE("%s failed to return the sound dose interface for module %s: not implemented",
946 __func__,
947 module.c_str());
948 return NO_INIT;
949 }
950
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100951 *soundDoseBinder = mSoundDose->asBinder();
952 ALOGI("%s using audio AIDL HAL sound dose interface", __func__);
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100953 return OK;
954}
jiabin872de702023-04-27 22:04:31 +0000955
956status_t DeviceHalAidl::prepareToDisconnectExternalDevice(const struct audio_port_v7* port) {
jiabin62750c22023-12-21 22:06:07 +0000957 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
958 TIME_CHECK();
959 if (mModule == nullptr) return NO_INIT;
960 if (port == nullptr) {
961 return BAD_VALUE;
962 }
963 const bool isInput = VALUE_OR_RETURN_STATUS(
964 ::aidl::android::portDirection(port->role, port->type)) ==
965 ::aidl::android::AudioPortDirection::INPUT;
966 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
967 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
968 if (aidlPort.ext.getTag() != AudioPortExt::device) {
969 ALOGE("%s: provided port is not a device port (module %s): %s",
970 __func__, mInstance.c_str(), aidlPort.toString().c_str());
971 return BAD_VALUE;
972 }
973 status_t status = NO_ERROR;
974 {
975 std::lock_guard l(mLock);
976 status = mMapper.prepareToDisconnectExternalDevice(aidlPort);
977 }
978 if (status == UNKNOWN_TRANSACTION) {
979 // If there is not AIDL API defined for `prepareToDisconnectExternalDevice`.
980 // Call `setConnectedState` instead.
981 RETURN_STATUS_IF_ERROR(setConnectedState(port, false /*connected*/));
982 std::lock_guard l(mLock);
983 mDeviceDisconnectionNotified.insert(port->id);
984 // Return that there was no error as otherwise the disconnection procedure will not be
985 // considered complete for upper layers, and 'setConnectedState' will not be called again
986 return OK;
987 } else {
988 return status;
989 }
jiabin872de702023-04-27 22:04:31 +0000990}
991
Mikhail Naganove93a0862023-03-15 17:06:59 -0700992status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
Mikhail Naganovae9063d2023-11-07 16:43:51 -0800993 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700994 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700995 if (mModule == nullptr) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700996 if (port == nullptr) {
997 return BAD_VALUE;
998 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700999 if (!connected) {
1000 std::lock_guard l(mLock);
1001 if (mDeviceDisconnectionNotified.erase(port->id) > 0) {
1002 // For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
jiabin62750c22023-12-21 22:06:07 +00001003 // and then call `setConnectedState`. If `prepareToDisconnectExternalDevice` doesn't
1004 // exit, `setConnectedState` will be called when calling
1005 // `prepareToDisconnectExternalDevice`. Do not call to the HAL if previous call is
1006 // successful. Also remove the cache here to avoid a large cache after a long run.
Mikhail Naganovac9d4e72023-10-23 12:00:09 -07001007 return OK;
1008 }
jiabin872de702023-04-27 22:04:31 +00001009 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001010 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
1011 ::aidl::android::AudioPortDirection::INPUT;
1012 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
1013 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
1014 if (aidlPort.ext.getTag() != AudioPortExt::device) {
1015 ALOGE("%s: provided port is not a device port (module %s): %s",
1016 __func__, mInstance.c_str(), aidlPort.toString().c_str());
1017 return BAD_VALUE;
1018 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -07001019 std::lock_guard l(mLock);
1020 return mMapper.setDevicePortConnectedState(aidlPort, connected);
Mikhail Naganove93a0862023-03-15 17:06:59 -07001021}
1022
1023status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
1024 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -07001025 if (mModule == nullptr) return NO_INIT;
1026 {
1027 std::lock_guard l(mLock);
Mikhail Naganova317a802024-03-15 18:03:10 +00001028 mMapper.resetUnusedPatchesAndPortConfigs();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -07001029 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001030 ModuleDebug debug{ .simulateDeviceConnections = enabled };
1031 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
1032 // This is important to log as it affects HAL behavior.
1033 if (status == OK) {
1034 ALOGI("%s: set enabled: %d", __func__, enabled);
1035 } else {
1036 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
1037 }
1038 return status;
1039}
1040
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001041status_t DeviceHalAidl::filterAndRetrieveBtA2dpParameters(
1042 AudioParameter &keys, AudioParameter *result) {
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001043 if (String8 key = String8(AudioParameter::keyReconfigA2dpSupported); keys.containsKey(key)) {
1044 keys.remove(key);
David Lia7761ed2023-11-03 17:22:07 +00001045 if (mBluetoothA2dp != nullptr) {
1046 bool supports;
1047 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1048 mBluetoothA2dp->supportsOffloadReconfiguration(&supports)));
1049 result->addInt(key, supports ? 1 : 0);
1050 } else {
1051 ALOGI("%s: no IBluetoothA2dp on %s", __func__, mInstance.c_str());
1052 result->addInt(key, 0);
1053 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001054 }
1055 return OK;
1056}
1057
Eric Laurent7e3c0832023-11-30 15:04:50 +01001058status_t DeviceHalAidl::filterAndRetrieveBtLeParameters(
1059 AudioParameter &keys, AudioParameter *result) {
1060 if (String8 key = String8(AudioParameter::keyReconfigLeSupported); keys.containsKey(key)) {
1061 keys.remove(key);
1062 if (mBluetoothLe != nullptr) {
1063 bool supports;
1064 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1065 mBluetoothLe->supportsOffloadReconfiguration(&supports)));
1066 result->addInt(key, supports ? 1 : 0);
1067 } else {
1068 ALOGI("%s: no mBluetoothLe on %s", __func__, mInstance.c_str());
1069 result->addInt(key, 0);
1070 }
1071 }
1072 return OK;
1073}
1074
Mikhail Naganovccc82112023-04-27 18:14:15 -07001075status_t DeviceHalAidl::filterAndUpdateBtA2dpParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001076 std::optional<bool> a2dpEnabled;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001077 std::optional<std::vector<VendorParameter>> reconfigureOffload;
Mikhail Naganovccc82112023-04-27 18:14:15 -07001078 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1079 parameters, String8(AudioParameter::keyBtA2dpSuspended),
1080 [&a2dpEnabled](const String8& trueOrFalse) {
1081 if (trueOrFalse == AudioParameter::valueTrue) {
1082 a2dpEnabled = false; // 'suspended' == true
1083 return OK;
1084 } else if (trueOrFalse == AudioParameter::valueFalse) {
1085 a2dpEnabled = true; // 'suspended' == false
1086 return OK;
1087 }
1088 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1089 AudioParameter::keyBtA2dpSuspended, trueOrFalse.c_str());
1090 return BAD_VALUE;
1091 }));
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001092 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1093 parameters, String8(AudioParameter::keyReconfigA2dp),
1094 [&](const String8& value) -> status_t {
Mikhail Naganove5011002024-01-26 10:57:19 -08001095 std::vector<VendorParameter> result;
1096 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1097 mVendorExt->parseBluetoothA2dpReconfigureOffload(
1098 std::string(value.c_str()), &result)));
1099 reconfigureOffload = std::move(result);
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001100 return OK;
1101 }));
Mikhail Naganovccc82112023-04-27 18:14:15 -07001102 if (mBluetoothA2dp != nullptr && a2dpEnabled.has_value()) {
1103 return statusTFromBinderStatus(mBluetoothA2dp->setEnabled(a2dpEnabled.value()));
1104 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001105 if (mBluetoothA2dp != nullptr && reconfigureOffload.has_value()) {
1106 return statusTFromBinderStatus(mBluetoothA2dp->reconfigureOffload(
1107 reconfigureOffload.value()));
1108 }
Mikhail Naganovccc82112023-04-27 18:14:15 -07001109 return OK;
1110}
1111
1112status_t DeviceHalAidl::filterAndUpdateBtHfpParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001113 IBluetooth::HfpConfig hfpConfig;
1114 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1115 parameters, String8(AudioParameter::keyBtHfpEnable),
1116 [&hfpConfig](const String8& trueOrFalse) {
1117 if (trueOrFalse == AudioParameter::valueTrue) {
1118 hfpConfig.isEnabled = Boolean{ .value = true };
1119 return OK;
1120 } else if (trueOrFalse == AudioParameter::valueFalse) {
1121 hfpConfig.isEnabled = Boolean{ .value = false };
1122 return OK;
1123 }
1124 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1125 AudioParameter::keyBtHfpEnable, trueOrFalse.c_str());
1126 return BAD_VALUE;
1127 }));
1128 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1129 parameters, String8(AudioParameter::keyBtHfpSamplingRate),
1130 [&hfpConfig](int sampleRate) {
1131 return sampleRate > 0 ?
1132 hfpConfig.sampleRate = Int{ .value = sampleRate }, OK : BAD_VALUE;
1133 }));
1134 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1135 parameters, String8(AudioParameter::keyBtHfpVolume),
1136 [&hfpConfig](int volume0to15) {
1137 if (volume0to15 >= 0 && volume0to15 <= 15) {
1138 hfpConfig.volume = Float{ .value = volume0to15 / 15.0f };
1139 return OK;
1140 }
1141 return BAD_VALUE;
1142 }));
1143 if (mBluetooth != nullptr && hfpConfig != IBluetooth::HfpConfig{}) {
1144 IBluetooth::HfpConfig newHfpConfig;
1145 return statusTFromBinderStatus(mBluetooth->setHfpConfig(hfpConfig, &newHfpConfig));
1146 }
1147 return OK;
1148}
1149
1150status_t DeviceHalAidl::filterAndUpdateBtLeParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001151 std::optional<bool> leEnabled;
Eric Laurent7e3c0832023-11-30 15:04:50 +01001152 std::optional<std::vector<VendorParameter>> reconfigureOffload;
Mikhail Naganovccc82112023-04-27 18:14:15 -07001153 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1154 parameters, String8(AudioParameter::keyBtLeSuspended),
1155 [&leEnabled](const String8& trueOrFalse) {
1156 if (trueOrFalse == AudioParameter::valueTrue) {
1157 leEnabled = false; // 'suspended' == true
1158 return OK;
1159 } else if (trueOrFalse == AudioParameter::valueFalse) {
1160 leEnabled = true; // 'suspended' == false
1161 return OK;
1162 }
1163 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1164 AudioParameter::keyBtLeSuspended, trueOrFalse.c_str());
1165 return BAD_VALUE;
1166 }));
Eric Laurent7e3c0832023-11-30 15:04:50 +01001167 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1168 parameters, String8(AudioParameter::keyReconfigLe),
1169 [&](const String8& value) -> status_t {
1170 if (mVendorExt != nullptr) {
1171 std::vector<VendorParameter> result;
1172 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1173 mVendorExt->parseBluetoothLeReconfigureOffload(
1174 std::string(value.c_str()), &result)));
1175 reconfigureOffload = std::move(result);
1176 } else {
1177 reconfigureOffload = std::vector<VendorParameter>();
1178 }
1179 return OK;
1180 }));
Mikhail Naganovccc82112023-04-27 18:14:15 -07001181 if (mBluetoothLe != nullptr && leEnabled.has_value()) {
1182 return statusTFromBinderStatus(mBluetoothLe->setEnabled(leEnabled.value()));
1183 }
Eric Laurent7e3c0832023-11-30 15:04:50 +01001184 if (mBluetoothLe != nullptr && reconfigureOffload.has_value()) {
1185 return statusTFromBinderStatus(mBluetoothLe->reconfigureOffload(
1186 reconfigureOffload.value()));
1187 }
Mikhail Naganovccc82112023-04-27 18:14:15 -07001188 return OK;
1189}
1190
1191status_t DeviceHalAidl::filterAndUpdateBtScoParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001192 IBluetooth::ScoConfig scoConfig;
1193 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1194 parameters, String8(AudioParameter::keyBtSco),
1195 [&scoConfig](const String8& onOrOff) {
1196 if (onOrOff == AudioParameter::valueOn) {
1197 scoConfig.isEnabled = Boolean{ .value = true };
1198 return OK;
1199 } else if (onOrOff == AudioParameter::valueOff) {
1200 scoConfig.isEnabled = Boolean{ .value = false };
1201 return OK;
1202 }
1203 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1204 AudioParameter::keyBtSco, onOrOff.c_str());
1205 return BAD_VALUE;
1206 }));
1207 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1208 parameters, String8(AudioParameter::keyBtScoHeadsetName),
1209 [&scoConfig](const String8& name) {
1210 scoConfig.debugName = name;
1211 return OK;
1212 }));
1213 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1214 parameters, String8(AudioParameter::keyBtNrec),
1215 [&scoConfig](const String8& onOrOff) {
1216 if (onOrOff == AudioParameter::valueOn) {
1217 scoConfig.isNrecEnabled = Boolean{ .value = true };
1218 return OK;
1219 } else if (onOrOff == AudioParameter::valueOff) {
1220 scoConfig.isNrecEnabled = Boolean{ .value = false };
1221 return OK;
1222 }
1223 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1224 AudioParameter::keyBtNrec, onOrOff.c_str());
1225 return BAD_VALUE;
1226 }));
1227 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1228 parameters, String8(AudioParameter::keyBtScoWb),
1229 [&scoConfig](const String8& onOrOff) {
1230 if (onOrOff == AudioParameter::valueOn) {
1231 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO_WB;
1232 return OK;
1233 } else if (onOrOff == AudioParameter::valueOff) {
1234 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO;
1235 return OK;
1236 }
1237 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1238 AudioParameter::keyBtScoWb, onOrOff.c_str());
1239 return BAD_VALUE;
1240 }));
1241 if (mBluetooth != nullptr && scoConfig != IBluetooth::ScoConfig{}) {
1242 IBluetooth::ScoConfig newScoConfig;
1243 return statusTFromBinderStatus(mBluetooth->setScoConfig(scoConfig, &newScoConfig));
1244 }
1245 return OK;
1246}
1247
Mikhail Naganove92c34b2023-05-31 14:24:48 -07001248status_t DeviceHalAidl::filterAndUpdateScreenParameters(AudioParameter &parameters) {
Mikhail Naganove92c34b2023-05-31 14:24:48 -07001249 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1250 parameters, String8(AudioParameter::keyScreenState),
1251 [&](const String8& onOrOff) -> status_t {
1252 std::optional<bool> isTurnedOn;
1253 if (onOrOff == AudioParameter::valueOn) {
1254 isTurnedOn = true;
1255 } else if (onOrOff == AudioParameter::valueOff) {
1256 isTurnedOn = false;
1257 }
1258 if (!isTurnedOn.has_value()) {
1259 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1260 AudioParameter::keyScreenState, onOrOff.c_str());
1261 return BAD_VALUE;
1262 }
1263 return statusTFromBinderStatus(
1264 mModule->updateScreenState(isTurnedOn.value()));
1265 }));
1266 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1267 parameters, String8(AudioParameter::keyScreenRotation),
1268 [&](int rotationDegrees) -> status_t {
1269 IModule::ScreenRotation rotation;
1270 switch (rotationDegrees) {
1271 case 0: rotation = IModule::ScreenRotation::DEG_0; break;
1272 case 90: rotation = IModule::ScreenRotation::DEG_90; break;
1273 case 180: rotation = IModule::ScreenRotation::DEG_180; break;
1274 case 270: rotation = IModule::ScreenRotation::DEG_270; break;
1275 default:
1276 ALOGE("setParameters: parameter key \"%s\" has invalid value %d",
1277 AudioParameter::keyScreenRotation, rotationDegrees);
1278 return BAD_VALUE;
1279 }
1280 return statusTFromBinderStatus(mModule->updateScreenRotation(rotation));
1281 }));
1282 return OK;
1283}
1284
Mikhail Naganovb9a81312023-07-18 13:55:34 -07001285status_t DeviceHalAidl::filterAndUpdateTelephonyParameters(AudioParameter &parameters) {
Mikhail Naganovb9a81312023-07-18 13:55:34 -07001286 using TtyMode = ITelephony::TelecomConfig::TtyMode;
1287 ITelephony::TelecomConfig telConfig;
1288 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1289 parameters, String8(AudioParameter::keyTtyMode),
1290 [&telConfig](const String8& mode) {
1291 if (mode == AudioParameter::valueTtyModeOff) {
1292 telConfig.ttyMode = TtyMode::OFF;
1293 return OK;
1294 } else if (mode == AudioParameter::valueTtyModeFull) {
1295 telConfig.ttyMode = TtyMode::FULL;
1296 return OK;
1297 } else if (mode == AudioParameter::valueTtyModeHco) {
1298 telConfig.ttyMode = TtyMode::HCO;
1299 return OK;
1300 } else if (mode == AudioParameter::valueTtyModeVco) {
1301 telConfig.ttyMode = TtyMode::VCO;
1302 return OK;
1303 }
1304 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1305 AudioParameter::keyTtyMode, mode.c_str());
1306 return BAD_VALUE;
1307 }));
1308 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1309 parameters, String8(AudioParameter::keyHacSetting),
1310 [&telConfig](const String8& onOrOff) {
1311 if (onOrOff == AudioParameter::valueHacOn) {
1312 telConfig.isHacEnabled = Boolean{ .value = true };
1313 return OK;
1314 } else if (onOrOff == AudioParameter::valueHacOff) {
1315 telConfig.isHacEnabled = Boolean{ .value = false };
1316 return OK;
1317 }
1318 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1319 AudioParameter::keyHacSetting, onOrOff.c_str());
1320 return BAD_VALUE;
1321 }));
1322 if (mTelephony != nullptr && telConfig != ITelephony::TelecomConfig{}) {
1323 ITelephony::TelecomConfig newTelConfig;
1324 return statusTFromBinderStatus(
1325 mTelephony->setTelecomConfig(telConfig, &newTelConfig));
1326 }
1327 return OK;
1328}
1329
Mikhail Naganovdfd594e2023-02-08 16:59:41 -08001330void DeviceHalAidl::clearCallbacks(void* cookie) {
1331 std::lock_guard l(mLock);
1332 mCallbacks.erase(cookie);
1333}
1334
1335sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1336 return getCallbackImpl(cookie, &Callbacks::out);
1337}
1338
1339void DeviceHalAidl::setStreamOutCallback(
1340 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1341 setCallbackImpl(cookie, &Callbacks::out, cb);
1342}
1343
1344sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1345 void* cookie) {
1346 return getCallbackImpl(cookie, &Callbacks::event);
1347}
1348
1349void DeviceHalAidl::setStreamOutEventCallback(
1350 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1351 setCallbackImpl(cookie, &Callbacks::event, cb);
1352}
1353
1354sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1355 void* cookie) {
1356 return getCallbackImpl(cookie, &Callbacks::latency);
1357}
1358
1359void DeviceHalAidl::setStreamOutLatencyModeCallback(
1360 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1361 setCallbackImpl(cookie, &Callbacks::latency, cb);
1362}
1363
1364template<class C>
1365sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1366 std::lock_guard l(mLock);
1367 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1368 return ((it->second).*field).promote();
1369 }
1370 return nullptr;
1371}
1372template<class C>
1373void DeviceHalAidl::setCallbackImpl(
1374 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1375 std::lock_guard l(mLock);
1376 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1377 (it->second).*field = cb;
1378 }
1379}
1380
Mikhail Naganov31d46652023-01-10 18:29:25 +00001381} // namespace android