blob: 14765f6bc924d347759b2a1c07b4d1876bf43116 [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 Naganove93a0862023-03-15 17:06:59 -0700481 *outStream = 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 Naganovdfd594e2023-02-08 16:59:41 -0800483 void* cbCookie = (*outStream).get();
484 {
485 std::lock_guard l(mLock);
486 mCallbacks.emplace(cbCookie, Callbacks{});
Mikhail Naganov78f7f9a2023-11-16 15:49:23 -0800487 mMapper.addStream(*outStream, mixPortConfig.id, aidlPatch.id);
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800488 }
489 if (streamCb) streamCb->setCookie(cbCookie);
490 eventCb->setCookie(cbCookie);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800491 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000492 return OK;
493}
494
Mikhail Naganov31d46652023-01-10 18:29:25 +0000495status_t DeviceHalAidl::openInputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800496 audio_io_handle_t handle, audio_devices_t devices,
497 struct audio_config* config, audio_input_flags_t flags,
498 const char* address, audio_source_t source,
499 audio_devices_t outputDevice, const char* outputDeviceAddress,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000500 sp<StreamInHalInterface>* inStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800501 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700502 TIME_CHECK();
503 if (mModule == nullptr) return NO_INIT;
504 if (inStream == nullptr || config == nullptr) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000505 return BAD_VALUE;
506 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700507 constexpr bool isInput = true;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800508 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
509 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
510 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700511 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, isInput));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800512 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
513 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
514 int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
515 ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
516 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
517 AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
518 ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
519 AudioPortConfig mixPortConfig;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700520 AudioPatch aidlPatch;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700521 Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
522 {
523 std::lock_guard l(mLock);
524 RETURN_STATUS_IF_ERROR(mMapper.prepareToOpenStream(
525 aidlHandle, aidlDevice, aidlFlags, aidlSource,
526 &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
527 }
528 *config = VALUE_OR_RETURN_STATUS(
529 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(aidlConfig, isInput));
Mikhail Naganovca92a5c2023-12-07 14:00:48 -0800530 if (mixPortConfig.id == 0) return BAD_VALUE; // HAL suggests a different config.
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800531 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
532 args.portConfigId = mixPortConfig.id;
533 RecordTrackMetadata aidlTrackMetadata{
534 .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
535 if (outputDevice != AUDIO_DEVICE_NONE) {
536 aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
537 ::aidl::android::legacy2aidl_audio_device_AudioDevice(
538 outputDevice, outputDeviceAddress));
539 }
540 args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
541 args.bufferSizeFrames = aidlConfig.frameCount;
542 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
543 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800544 StreamContextAidl context(ret.desc, false /*isAsynchronous*/);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800545 if (!context.isValid()) {
546 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
547 __func__, ret.desc.toString().c_str());
548 return NO_INIT;
549 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700550 *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700551 std::move(ret.stream), mVendorExt, this /*micInfoProvider*/);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700552 {
553 std::lock_guard l(mLock);
Mikhail Naganov78f7f9a2023-11-16 15:49:23 -0800554 mMapper.addStream(*inStream, mixPortConfig.id, aidlPatch.id);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700555 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800556 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000557 return OK;
558}
559
560status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700561 if (supportsPatches == nullptr) {
562 return BAD_VALUE;
563 }
Shunkai Yao51202502022-12-12 06:11:46 +0000564 *supportsPatches = true;
565 return OK;
566}
567
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800568status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
569 const struct audio_port_config* sources,
570 unsigned int num_sinks,
571 const struct audio_port_config* sinks,
572 audio_patch_handle_t* patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800573 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000574 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700575 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800576 if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
577 sources == nullptr || sinks == nullptr || patch == nullptr) {
578 return BAD_VALUE;
579 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800580 // When the patch handle (*patch) is AUDIO_PATCH_HANDLE_NONE, it means
581 // the framework wants to create a new patch. The handle has to be generated
582 // by the HAL. Since handles generated this way can only be unique within
583 // a HAL module, the framework generates a globally unique handle, and maps
584 // it on the <HAL module, patch handle> pair.
585 // When the patch handle is set, it meant the framework intends to update
586 // an existing patch.
587 //
588 // This behavior corresponds to HAL module behavior, with the only difference
589 // that the HAL module uses `int32_t` for patch IDs. The following assert ensures
590 // that both the framework and the HAL use the same value for "no ID":
591 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700592 int32_t aidlPatchId = static_cast<int32_t>(*patch);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800593
594 // Upon conversion, mix port configs contain audio configuration, while
595 // device port configs contain device address. This data is used to find
596 // or create HAL configs.
597 std::vector<AudioPortConfig> aidlSources, aidlSinks;
598 for (unsigned int i = 0; i < num_sources; ++i) {
599 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
600 sources[i].role, sources[i].type)) ==
601 ::aidl::android::AudioPortDirection::INPUT;
602 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
603 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
604 sources[i], isInput, 0)));
605 }
606 for (unsigned int i = 0; i < num_sinks; ++i) {
607 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
608 sinks[i].role, sinks[i].type)) ==
609 ::aidl::android::AudioPortDirection::INPUT;
610 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
611 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
612 sinks[i], isInput, 0)));
613 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700614 Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
615 {
616 std::lock_guard l(mLock);
617 RETURN_STATUS_IF_ERROR(mMapper.createOrUpdatePatch(
618 aidlSources, aidlSinks, &aidlPatchId, &cleanups));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800619 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700620 *patch = static_cast<audio_patch_handle_t>(aidlPatchId);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800621 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000622 return OK;
623}
624
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800625status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800626 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000627 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700628 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800629 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
630 if (patch == AUDIO_PATCH_HANDLE_NONE) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800631 return BAD_VALUE;
632 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700633 std::lock_guard l(mLock);
634 RETURN_STATUS_IF_ERROR(mMapper.releaseAudioPatch(static_cast<int32_t>(patch)));
Shunkai Yao51202502022-12-12 06:11:46 +0000635 return OK;
636}
637
Mikhail Naganove93a0862023-03-15 17:06:59 -0700638status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700639 if (port == nullptr) {
640 return BAD_VALUE;
641 }
642 audio_port_v7 portV7;
643 audio_populate_audio_port_v7(port, &portV7);
644 RETURN_STATUS_IF_ERROR(getAudioPort(&portV7));
645 return audio_populate_audio_port(&portV7, port) ? OK : BAD_VALUE;
646}
647
648status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
649 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
650 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700651 if (mModule == nullptr) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700652 if (port == nullptr) {
653 return BAD_VALUE;
654 }
655 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
656 ::aidl::android::AudioPortDirection::INPUT;
657 auto aidlPort = VALUE_OR_RETURN_STATUS(
658 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
659 if (aidlPort.ext.getTag() != AudioPortExt::device) {
660 ALOGE("%s: provided port is not a device port (module %s): %s",
661 __func__, mInstance.c_str(), aidlPort.toString().c_str());
662 return BAD_VALUE;
663 }
664 const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
665 // It seems that we don't have to call HAL since all valid ports have been added either
666 // during initialization, or while handling connection of an external device.
Mikhail Naganove93a0862023-03-15 17:06:59 -0700667 const int32_t fwkId = aidlPort.id;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700668 {
669 std::lock_guard l(mLock);
670 RETURN_STATUS_IF_ERROR(mMapper.getAudioPortCached(matchDevice, &aidlPort));
671 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700672 aidlPort.id = fwkId;
673 *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
674 aidlPort, isInput));
675 return OK;
676}
677
jiabin12537fc2023-10-12 17:56:08 +0000678status_t DeviceHalAidl::getAudioMixPort(const struct audio_port_v7 *devicePort,
679 struct audio_port_v7 *mixPort) {
680 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700681 TIME_CHECK();
682 if (mModule == nullptr) return NO_INIT;
683 if (devicePort == nullptr || mixPort == nullptr ||
684 devicePort->type != AUDIO_PORT_TYPE_DEVICE || mixPort->type != AUDIO_PORT_TYPE_MIX) {
jiabin12537fc2023-10-12 17:56:08 +0000685 return BAD_VALUE;
686 }
687 const int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
688 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(mixPort->ext.mix.handle));
jiabin12537fc2023-10-12 17:56:08 +0000689 AudioPort port;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700690 {
691 std::lock_guard l(mLock);
692 RETURN_STATUS_IF_ERROR(mMapper.getAudioMixPort(aidlHandle, &port));
jiabin12537fc2023-10-12 17:56:08 +0000693 }
694 const bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
695 mixPort->role, mixPort->type)) == ::aidl::android::AudioPortDirection::INPUT;
696 *mixPort = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
697 port, isInput));
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700698 return OK;
jiabin12537fc2023-10-12 17:56:08 +0000699}
700
Mikhail Naganove93a0862023-03-15 17:06:59 -0700701status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
702 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
703 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700704 if (mModule == nullptr) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700705 if (config == nullptr) {
706 return BAD_VALUE;
707 }
708 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
709 config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
710 AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
711 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
712 *config, isInput, 0 /*portId*/));
713 AudioPortConfig portConfig;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700714 std::lock_guard l(mLock);
Mikhail Naganovca92a5c2023-12-07 14:00:48 -0800715 return mMapper.setPortConfig(requestedPortConfig, std::set<int32_t>(), &portConfig);
Shunkai Yao51202502022-12-12 06:11:46 +0000716}
717
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800718MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700719 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
720 TIME_CHECK();
721 if (!mModule) return {};
722 std::lock_guard l(mLock);
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800723 if (mMicrophones.status == Microphones::Status::UNKNOWN) {
724 TIME_CHECK();
725 std::vector<MicrophoneInfo> aidlInfo;
726 status_t status = statusTFromBinderStatus(mModule->getMicrophones(&aidlInfo));
727 if (status == OK) {
728 mMicrophones.status = Microphones::Status::QUERIED;
729 mMicrophones.info = std::move(aidlInfo);
730 } else if (status == INVALID_OPERATION) {
731 mMicrophones.status = Microphones::Status::NOT_SUPPORTED;
732 } else {
733 ALOGE("%s: Unexpected status from 'IModule.getMicrophones': %d", __func__, status);
734 return {};
735 }
736 }
737 if (mMicrophones.status == Microphones::Status::QUERIED) {
738 return &mMicrophones.info;
739 }
740 return {}; // NOT_SUPPORTED
741}
742
Shunkai Yao51202502022-12-12 06:11:46 +0000743status_t DeviceHalAidl::getMicrophones(
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800744 std::vector<audio_microphone_characteristic_t>* microphones) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700745 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
746 TIME_CHECK();
747 if (mModule == nullptr) return NO_INIT;
748 if (microphones == nullptr) {
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800749 return BAD_VALUE;
750 }
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800751 auto staticInfo = getMicrophoneInfo();
752 if (!staticInfo) return INVALID_OPERATION;
753 std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
754 emptyDynamicInfo.reserve(staticInfo->size());
755 std::transform(staticInfo->begin(), staticInfo->end(), std::back_inserter(emptyDynamicInfo),
756 [](const auto& info) { return MicrophoneDynamicInfo{ .id = info.id }; });
757 *microphones = VALUE_OR_RETURN_STATUS(
758 ::aidl::android::convertContainers<std::vector<audio_microphone_characteristic_t>>(
759 *staticInfo, emptyDynamicInfo,
760 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t)
761 );
Shunkai Yao51202502022-12-12 06:11:46 +0000762 return OK;
763}
764
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700765status_t DeviceHalAidl::addDeviceEffect(
766 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700767 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700768 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700769 if (mModule == nullptr) return NO_INIT;
770 if (device == nullptr || effect == nullptr) {
Shunkai Yao51202502022-12-12 06:11:46 +0000771 return BAD_VALUE;
772 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700773 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
774 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
775 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
776 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
777 *device, isInput, 0));
778 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
779 ALOGE("%s: provided port config is not a device port config: %s",
780 __func__, requestedPortConfig.toString().c_str());
781 return BAD_VALUE;
782 }
783 AudioPortConfig devicePortConfig;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700784 Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
785 {
786 std::lock_guard l(mLock);
Mikhail Naganovca92a5c2023-12-07 14:00:48 -0800787 RETURN_STATUS_IF_ERROR(mMapper.setPortConfig(
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700788 requestedPortConfig, {} /*destinationPortIds*/, &devicePortConfig, &cleanups));
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700789 }
790 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
791 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->addDeviceEffect(
792 devicePortConfig.id, aidlEffect->getIEffect())));
793 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000794 return OK;
795}
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700796status_t DeviceHalAidl::removeDeviceEffect(
797 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700798 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700799 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700800 if (mModule == nullptr) return NO_INIT;
801 if (device == nullptr || effect == nullptr) {
Shunkai Yao51202502022-12-12 06:11:46 +0000802 return BAD_VALUE;
803 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700804 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
805 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
806 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
807 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
808 *device, isInput, 0));
809 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
810 ALOGE("%s: provided port config is not a device port config: %s",
811 __func__, requestedPortConfig.toString().c_str());
812 return BAD_VALUE;
813 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700814 AudioPortConfig devicePortConfig;
815 {
816 std::lock_guard l(mLock);
817 RETURN_STATUS_IF_ERROR(mMapper.findPortConfig(
818 requestedPortConfig.ext.get<AudioPortExt::Tag::device>().device,
819 &devicePortConfig));
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700820 }
821 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
822 return statusTFromBinderStatus(mModule->removeDeviceEffect(
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700823 devicePortConfig.id, aidlEffect->getIEffect()));
Shunkai Yao51202502022-12-12 06:11:46 +0000824}
825
826status_t DeviceHalAidl::getMmapPolicyInfos(
David Li9cf5e622023-03-21 00:51:10 +0800827 media::audio::common::AudioMMapPolicyType policyType,
828 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700829 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000830 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700831 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov25bc9a22023-04-21 18:48:16 -0700832 AudioMMapPolicyType mmapPolicyType = VALUE_OR_RETURN_STATUS(
833 cpp2ndk_AudioMMapPolicyType(policyType));
David Li9cf5e622023-03-21 00:51:10 +0800834
835 std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
836
837 if (status_t status = statusTFromBinderStatus(
838 mModule->getMmapPolicyInfos(mmapPolicyType, &mmapPolicyInfos)); status != OK) {
839 return status;
840 }
841
842 *policyInfos = VALUE_OR_RETURN_STATUS(
843 convertContainer<std::vector<media::audio::common::AudioMMapPolicyInfo>>(
844 mmapPolicyInfos, ndk2cpp_AudioMMapPolicyInfo));
Shunkai Yao51202502022-12-12 06:11:46 +0000845 return OK;
846}
847
848int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700849 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000850 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700851 if (mModule == nullptr) return NO_INIT;
David Li9cf5e622023-03-21 00:51:10 +0800852 int32_t mixerBurstCount = 0;
853 if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
854 return mixerBurstCount;
855 }
856 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000857}
858
859int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700860 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000861 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700862 if (mModule == nullptr) return NO_INIT;
David Li9cf5e622023-03-21 00:51:10 +0800863 int32_t hardwareBurstMinUsec = 0;
864 if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
865 return hardwareBurstMinUsec;
866 }
867 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000868}
869
870error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700871 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000872 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700873 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700874 int32_t aidlHwAvSync;
875 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
876 return VALUE_OR_RETURN_STATUS(
877 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +0000878}
879
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000880status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
881 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700882 if (mModule == nullptr) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000883 return mModule->dump(fd, Args(args).args(), args.size());
David Li9cf5e622023-03-21 00:51:10 +0800884}
Shunkai Yao51202502022-12-12 06:11:46 +0000885
Eric Laurent7af6ee72023-06-29 11:44:54 +0200886status_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700887 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000888 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700889 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700890 if (supports == nullptr) {
891 return BAD_VALUE;
892 }
893 return statusTFromBinderStatus(mModule->supportsVariableLatency(supports));
Shunkai Yao51202502022-12-12 06:11:46 +0000894}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000895
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100896status_t DeviceHalAidl::getSoundDoseInterface(const std::string& module,
897 ::ndk::SpAIBinder* soundDoseBinder) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700898 if (soundDoseBinder == nullptr) {
899 return BAD_VALUE;
900 }
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100901 if (mSoundDose == nullptr) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700902 ALOGE("%s failed to retrieve the sound dose interface for module %s",
903 __func__, module.c_str());
904 return BAD_VALUE;
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100905 }
Vlad Popae1f33902023-10-30 19:48:25 -0700906
907 if (mSoundDose == nullptr) {
908 ALOGE("%s failed to return the sound dose interface for module %s: not implemented",
909 __func__,
910 module.c_str());
911 return NO_INIT;
912 }
913
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100914 *soundDoseBinder = mSoundDose->asBinder();
915 ALOGI("%s using audio AIDL HAL sound dose interface", __func__);
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100916 return OK;
917}
jiabin872de702023-04-27 22:04:31 +0000918
919status_t DeviceHalAidl::prepareToDisconnectExternalDevice(const struct audio_port_v7* port) {
jiabin62750c22023-12-21 22:06:07 +0000920 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
921 TIME_CHECK();
922 if (mModule == nullptr) return NO_INIT;
923 if (port == nullptr) {
924 return BAD_VALUE;
925 }
926 const bool isInput = VALUE_OR_RETURN_STATUS(
927 ::aidl::android::portDirection(port->role, port->type)) ==
928 ::aidl::android::AudioPortDirection::INPUT;
929 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
930 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
931 if (aidlPort.ext.getTag() != AudioPortExt::device) {
932 ALOGE("%s: provided port is not a device port (module %s): %s",
933 __func__, mInstance.c_str(), aidlPort.toString().c_str());
934 return BAD_VALUE;
935 }
936 status_t status = NO_ERROR;
937 {
938 std::lock_guard l(mLock);
939 status = mMapper.prepareToDisconnectExternalDevice(aidlPort);
940 }
941 if (status == UNKNOWN_TRANSACTION) {
942 // If there is not AIDL API defined for `prepareToDisconnectExternalDevice`.
943 // Call `setConnectedState` instead.
944 RETURN_STATUS_IF_ERROR(setConnectedState(port, false /*connected*/));
945 std::lock_guard l(mLock);
946 mDeviceDisconnectionNotified.insert(port->id);
947 // Return that there was no error as otherwise the disconnection procedure will not be
948 // considered complete for upper layers, and 'setConnectedState' will not be called again
949 return OK;
950 } else {
951 return status;
952 }
jiabin872de702023-04-27 22:04:31 +0000953}
954
Mikhail Naganove93a0862023-03-15 17:06:59 -0700955status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
Mikhail Naganovae9063d2023-11-07 16:43:51 -0800956 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700957 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700958 if (mModule == nullptr) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700959 if (port == nullptr) {
960 return BAD_VALUE;
961 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700962 if (!connected) {
963 std::lock_guard l(mLock);
964 if (mDeviceDisconnectionNotified.erase(port->id) > 0) {
965 // For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
jiabin62750c22023-12-21 22:06:07 +0000966 // and then call `setConnectedState`. If `prepareToDisconnectExternalDevice` doesn't
967 // exit, `setConnectedState` will be called when calling
968 // `prepareToDisconnectExternalDevice`. Do not call to the HAL if previous call is
969 // successful. Also remove the cache here to avoid a large cache after a long run.
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700970 return OK;
971 }
jiabin872de702023-04-27 22:04:31 +0000972 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700973 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
974 ::aidl::android::AudioPortDirection::INPUT;
975 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
976 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
977 if (aidlPort.ext.getTag() != AudioPortExt::device) {
978 ALOGE("%s: provided port is not a device port (module %s): %s",
979 __func__, mInstance.c_str(), aidlPort.toString().c_str());
980 return BAD_VALUE;
981 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700982 std::lock_guard l(mLock);
983 return mMapper.setDevicePortConnectedState(aidlPort, connected);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700984}
985
986status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
987 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700988 if (mModule == nullptr) return NO_INIT;
989 {
990 std::lock_guard l(mLock);
Mikhail Naganov15520da2024-01-17 11:15:20 -0800991 mMapper.resetUnusedPatchesPortConfigsAndPorts();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700992 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700993 ModuleDebug debug{ .simulateDeviceConnections = enabled };
994 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
995 // This is important to log as it affects HAL behavior.
996 if (status == OK) {
997 ALOGI("%s: set enabled: %d", __func__, enabled);
998 } else {
999 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
1000 }
1001 return status;
1002}
1003
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001004status_t DeviceHalAidl::filterAndRetrieveBtA2dpParameters(
1005 AudioParameter &keys, AudioParameter *result) {
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001006 if (String8 key = String8(AudioParameter::keyReconfigA2dpSupported); keys.containsKey(key)) {
1007 keys.remove(key);
David Lia7761ed2023-11-03 17:22:07 +00001008 if (mBluetoothA2dp != nullptr) {
1009 bool supports;
1010 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1011 mBluetoothA2dp->supportsOffloadReconfiguration(&supports)));
1012 result->addInt(key, supports ? 1 : 0);
1013 } else {
1014 ALOGI("%s: no IBluetoothA2dp on %s", __func__, mInstance.c_str());
1015 result->addInt(key, 0);
1016 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001017 }
1018 return OK;
1019}
1020
Eric Laurent7e3c0832023-11-30 15:04:50 +01001021status_t DeviceHalAidl::filterAndRetrieveBtLeParameters(
1022 AudioParameter &keys, AudioParameter *result) {
1023 if (String8 key = String8(AudioParameter::keyReconfigLeSupported); keys.containsKey(key)) {
1024 keys.remove(key);
1025 if (mBluetoothLe != nullptr) {
1026 bool supports;
1027 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1028 mBluetoothLe->supportsOffloadReconfiguration(&supports)));
1029 result->addInt(key, supports ? 1 : 0);
1030 } else {
1031 ALOGI("%s: no mBluetoothLe on %s", __func__, mInstance.c_str());
1032 result->addInt(key, 0);
1033 }
1034 }
1035 return OK;
1036}
1037
Mikhail Naganovccc82112023-04-27 18:14:15 -07001038status_t DeviceHalAidl::filterAndUpdateBtA2dpParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001039 std::optional<bool> a2dpEnabled;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001040 std::optional<std::vector<VendorParameter>> reconfigureOffload;
Mikhail Naganovccc82112023-04-27 18:14:15 -07001041 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1042 parameters, String8(AudioParameter::keyBtA2dpSuspended),
1043 [&a2dpEnabled](const String8& trueOrFalse) {
1044 if (trueOrFalse == AudioParameter::valueTrue) {
1045 a2dpEnabled = false; // 'suspended' == true
1046 return OK;
1047 } else if (trueOrFalse == AudioParameter::valueFalse) {
1048 a2dpEnabled = true; // 'suspended' == false
1049 return OK;
1050 }
1051 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1052 AudioParameter::keyBtA2dpSuspended, trueOrFalse.c_str());
1053 return BAD_VALUE;
1054 }));
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001055 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1056 parameters, String8(AudioParameter::keyReconfigA2dp),
1057 [&](const String8& value) -> status_t {
Mikhail Naganove5011002024-01-26 10:57:19 -08001058 std::vector<VendorParameter> result;
1059 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1060 mVendorExt->parseBluetoothA2dpReconfigureOffload(
1061 std::string(value.c_str()), &result)));
1062 reconfigureOffload = std::move(result);
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001063 return OK;
1064 }));
Mikhail Naganovccc82112023-04-27 18:14:15 -07001065 if (mBluetoothA2dp != nullptr && a2dpEnabled.has_value()) {
1066 return statusTFromBinderStatus(mBluetoothA2dp->setEnabled(a2dpEnabled.value()));
1067 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001068 if (mBluetoothA2dp != nullptr && reconfigureOffload.has_value()) {
1069 return statusTFromBinderStatus(mBluetoothA2dp->reconfigureOffload(
1070 reconfigureOffload.value()));
1071 }
Mikhail Naganovccc82112023-04-27 18:14:15 -07001072 return OK;
1073}
1074
1075status_t DeviceHalAidl::filterAndUpdateBtHfpParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001076 IBluetooth::HfpConfig hfpConfig;
1077 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1078 parameters, String8(AudioParameter::keyBtHfpEnable),
1079 [&hfpConfig](const String8& trueOrFalse) {
1080 if (trueOrFalse == AudioParameter::valueTrue) {
1081 hfpConfig.isEnabled = Boolean{ .value = true };
1082 return OK;
1083 } else if (trueOrFalse == AudioParameter::valueFalse) {
1084 hfpConfig.isEnabled = Boolean{ .value = false };
1085 return OK;
1086 }
1087 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1088 AudioParameter::keyBtHfpEnable, trueOrFalse.c_str());
1089 return BAD_VALUE;
1090 }));
1091 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1092 parameters, String8(AudioParameter::keyBtHfpSamplingRate),
1093 [&hfpConfig](int sampleRate) {
1094 return sampleRate > 0 ?
1095 hfpConfig.sampleRate = Int{ .value = sampleRate }, OK : BAD_VALUE;
1096 }));
1097 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1098 parameters, String8(AudioParameter::keyBtHfpVolume),
1099 [&hfpConfig](int volume0to15) {
1100 if (volume0to15 >= 0 && volume0to15 <= 15) {
1101 hfpConfig.volume = Float{ .value = volume0to15 / 15.0f };
1102 return OK;
1103 }
1104 return BAD_VALUE;
1105 }));
1106 if (mBluetooth != nullptr && hfpConfig != IBluetooth::HfpConfig{}) {
1107 IBluetooth::HfpConfig newHfpConfig;
1108 return statusTFromBinderStatus(mBluetooth->setHfpConfig(hfpConfig, &newHfpConfig));
1109 }
1110 return OK;
1111}
1112
1113status_t DeviceHalAidl::filterAndUpdateBtLeParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001114 std::optional<bool> leEnabled;
Eric Laurent7e3c0832023-11-30 15:04:50 +01001115 std::optional<std::vector<VendorParameter>> reconfigureOffload;
Mikhail Naganovccc82112023-04-27 18:14:15 -07001116 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1117 parameters, String8(AudioParameter::keyBtLeSuspended),
1118 [&leEnabled](const String8& trueOrFalse) {
1119 if (trueOrFalse == AudioParameter::valueTrue) {
1120 leEnabled = false; // 'suspended' == true
1121 return OK;
1122 } else if (trueOrFalse == AudioParameter::valueFalse) {
1123 leEnabled = true; // 'suspended' == false
1124 return OK;
1125 }
1126 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1127 AudioParameter::keyBtLeSuspended, trueOrFalse.c_str());
1128 return BAD_VALUE;
1129 }));
Eric Laurent7e3c0832023-11-30 15:04:50 +01001130 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1131 parameters, String8(AudioParameter::keyReconfigLe),
1132 [&](const String8& value) -> status_t {
1133 if (mVendorExt != nullptr) {
1134 std::vector<VendorParameter> result;
1135 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1136 mVendorExt->parseBluetoothLeReconfigureOffload(
1137 std::string(value.c_str()), &result)));
1138 reconfigureOffload = std::move(result);
1139 } else {
1140 reconfigureOffload = std::vector<VendorParameter>();
1141 }
1142 return OK;
1143 }));
Mikhail Naganovccc82112023-04-27 18:14:15 -07001144 if (mBluetoothLe != nullptr && leEnabled.has_value()) {
1145 return statusTFromBinderStatus(mBluetoothLe->setEnabled(leEnabled.value()));
1146 }
Eric Laurent7e3c0832023-11-30 15:04:50 +01001147 if (mBluetoothLe != nullptr && reconfigureOffload.has_value()) {
1148 return statusTFromBinderStatus(mBluetoothLe->reconfigureOffload(
1149 reconfigureOffload.value()));
1150 }
Mikhail Naganovccc82112023-04-27 18:14:15 -07001151 return OK;
1152}
1153
1154status_t DeviceHalAidl::filterAndUpdateBtScoParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001155 IBluetooth::ScoConfig scoConfig;
1156 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1157 parameters, String8(AudioParameter::keyBtSco),
1158 [&scoConfig](const String8& onOrOff) {
1159 if (onOrOff == AudioParameter::valueOn) {
1160 scoConfig.isEnabled = Boolean{ .value = true };
1161 return OK;
1162 } else if (onOrOff == AudioParameter::valueOff) {
1163 scoConfig.isEnabled = Boolean{ .value = false };
1164 return OK;
1165 }
1166 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1167 AudioParameter::keyBtSco, onOrOff.c_str());
1168 return BAD_VALUE;
1169 }));
1170 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1171 parameters, String8(AudioParameter::keyBtScoHeadsetName),
1172 [&scoConfig](const String8& name) {
1173 scoConfig.debugName = name;
1174 return OK;
1175 }));
1176 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1177 parameters, String8(AudioParameter::keyBtNrec),
1178 [&scoConfig](const String8& onOrOff) {
1179 if (onOrOff == AudioParameter::valueOn) {
1180 scoConfig.isNrecEnabled = Boolean{ .value = true };
1181 return OK;
1182 } else if (onOrOff == AudioParameter::valueOff) {
1183 scoConfig.isNrecEnabled = Boolean{ .value = false };
1184 return OK;
1185 }
1186 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1187 AudioParameter::keyBtNrec, onOrOff.c_str());
1188 return BAD_VALUE;
1189 }));
1190 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1191 parameters, String8(AudioParameter::keyBtScoWb),
1192 [&scoConfig](const String8& onOrOff) {
1193 if (onOrOff == AudioParameter::valueOn) {
1194 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO_WB;
1195 return OK;
1196 } else if (onOrOff == AudioParameter::valueOff) {
1197 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO;
1198 return OK;
1199 }
1200 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1201 AudioParameter::keyBtScoWb, onOrOff.c_str());
1202 return BAD_VALUE;
1203 }));
1204 if (mBluetooth != nullptr && scoConfig != IBluetooth::ScoConfig{}) {
1205 IBluetooth::ScoConfig newScoConfig;
1206 return statusTFromBinderStatus(mBluetooth->setScoConfig(scoConfig, &newScoConfig));
1207 }
1208 return OK;
1209}
1210
Mikhail Naganove92c34b2023-05-31 14:24:48 -07001211status_t DeviceHalAidl::filterAndUpdateScreenParameters(AudioParameter &parameters) {
Mikhail Naganove92c34b2023-05-31 14:24:48 -07001212 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1213 parameters, String8(AudioParameter::keyScreenState),
1214 [&](const String8& onOrOff) -> status_t {
1215 std::optional<bool> isTurnedOn;
1216 if (onOrOff == AudioParameter::valueOn) {
1217 isTurnedOn = true;
1218 } else if (onOrOff == AudioParameter::valueOff) {
1219 isTurnedOn = false;
1220 }
1221 if (!isTurnedOn.has_value()) {
1222 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1223 AudioParameter::keyScreenState, onOrOff.c_str());
1224 return BAD_VALUE;
1225 }
1226 return statusTFromBinderStatus(
1227 mModule->updateScreenState(isTurnedOn.value()));
1228 }));
1229 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1230 parameters, String8(AudioParameter::keyScreenRotation),
1231 [&](int rotationDegrees) -> status_t {
1232 IModule::ScreenRotation rotation;
1233 switch (rotationDegrees) {
1234 case 0: rotation = IModule::ScreenRotation::DEG_0; break;
1235 case 90: rotation = IModule::ScreenRotation::DEG_90; break;
1236 case 180: rotation = IModule::ScreenRotation::DEG_180; break;
1237 case 270: rotation = IModule::ScreenRotation::DEG_270; break;
1238 default:
1239 ALOGE("setParameters: parameter key \"%s\" has invalid value %d",
1240 AudioParameter::keyScreenRotation, rotationDegrees);
1241 return BAD_VALUE;
1242 }
1243 return statusTFromBinderStatus(mModule->updateScreenRotation(rotation));
1244 }));
1245 return OK;
1246}
1247
Mikhail Naganovb9a81312023-07-18 13:55:34 -07001248status_t DeviceHalAidl::filterAndUpdateTelephonyParameters(AudioParameter &parameters) {
Mikhail Naganovb9a81312023-07-18 13:55:34 -07001249 using TtyMode = ITelephony::TelecomConfig::TtyMode;
1250 ITelephony::TelecomConfig telConfig;
1251 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1252 parameters, String8(AudioParameter::keyTtyMode),
1253 [&telConfig](const String8& mode) {
1254 if (mode == AudioParameter::valueTtyModeOff) {
1255 telConfig.ttyMode = TtyMode::OFF;
1256 return OK;
1257 } else if (mode == AudioParameter::valueTtyModeFull) {
1258 telConfig.ttyMode = TtyMode::FULL;
1259 return OK;
1260 } else if (mode == AudioParameter::valueTtyModeHco) {
1261 telConfig.ttyMode = TtyMode::HCO;
1262 return OK;
1263 } else if (mode == AudioParameter::valueTtyModeVco) {
1264 telConfig.ttyMode = TtyMode::VCO;
1265 return OK;
1266 }
1267 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1268 AudioParameter::keyTtyMode, mode.c_str());
1269 return BAD_VALUE;
1270 }));
1271 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1272 parameters, String8(AudioParameter::keyHacSetting),
1273 [&telConfig](const String8& onOrOff) {
1274 if (onOrOff == AudioParameter::valueHacOn) {
1275 telConfig.isHacEnabled = Boolean{ .value = true };
1276 return OK;
1277 } else if (onOrOff == AudioParameter::valueHacOff) {
1278 telConfig.isHacEnabled = Boolean{ .value = false };
1279 return OK;
1280 }
1281 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1282 AudioParameter::keyHacSetting, onOrOff.c_str());
1283 return BAD_VALUE;
1284 }));
1285 if (mTelephony != nullptr && telConfig != ITelephony::TelecomConfig{}) {
1286 ITelephony::TelecomConfig newTelConfig;
1287 return statusTFromBinderStatus(
1288 mTelephony->setTelecomConfig(telConfig, &newTelConfig));
1289 }
1290 return OK;
1291}
1292
Mikhail Naganovdfd594e2023-02-08 16:59:41 -08001293void DeviceHalAidl::clearCallbacks(void* cookie) {
1294 std::lock_guard l(mLock);
1295 mCallbacks.erase(cookie);
1296}
1297
1298sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1299 return getCallbackImpl(cookie, &Callbacks::out);
1300}
1301
1302void DeviceHalAidl::setStreamOutCallback(
1303 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1304 setCallbackImpl(cookie, &Callbacks::out, cb);
1305}
1306
1307sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1308 void* cookie) {
1309 return getCallbackImpl(cookie, &Callbacks::event);
1310}
1311
1312void DeviceHalAidl::setStreamOutEventCallback(
1313 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1314 setCallbackImpl(cookie, &Callbacks::event, cb);
1315}
1316
1317sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1318 void* cookie) {
1319 return getCallbackImpl(cookie, &Callbacks::latency);
1320}
1321
1322void DeviceHalAidl::setStreamOutLatencyModeCallback(
1323 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1324 setCallbackImpl(cookie, &Callbacks::latency, cb);
1325}
1326
1327template<class C>
1328sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1329 std::lock_guard l(mLock);
1330 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1331 return ((it->second).*field).promote();
1332 }
1333 return nullptr;
1334}
1335template<class C>
1336void DeviceHalAidl::setCallbackImpl(
1337 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1338 std::lock_guard l(mLock);
1339 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1340 (it->second).*field = cb;
1341 }
1342}
1343
Mikhail Naganov31d46652023-01-10 18:29:25 +00001344} // namespace android