blob: f8656038187c40751674707595105bdf91347303 [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 Naganov5b1eed12023-01-25 11:29:11 -0800592
593 // Upon conversion, mix port configs contain audio configuration, while
594 // device port configs contain device address. This data is used to find
595 // or create HAL configs.
596 std::vector<AudioPortConfig> aidlSources, aidlSinks;
597 for (unsigned int i = 0; i < num_sources; ++i) {
598 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
599 sources[i].role, sources[i].type)) ==
600 ::aidl::android::AudioPortDirection::INPUT;
601 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
602 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
603 sources[i], isInput, 0)));
604 }
605 for (unsigned int i = 0; i < num_sinks; ++i) {
606 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
607 sinks[i].role, sinks[i].type)) ==
608 ::aidl::android::AudioPortDirection::INPUT;
609 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
610 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
611 sinks[i], isInput, 0)));
612 }
Mikhail Naganov6b5da722024-03-14 12:59:32 -0700613 int32_t aidlPatchId = static_cast<int32_t>(*patch);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700614 Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
615 {
616 std::lock_guard l(mLock);
Mikhail Naganov6b5da722024-03-14 12:59:32 -0700617 // Check for patches that only exist for the framework, or have different HAL patch ID.
618 if (int32_t aidlHalPatchId = mMapper.findFwkPatch(aidlPatchId); aidlHalPatchId != 0) {
619 if (aidlHalPatchId == aidlPatchId) {
620 // This patch was previously released by the HAL. Thus we need to pass '0'
621 // to the HAL to obtain a new patch.
622 int32_t newAidlPatchId = 0;
623 RETURN_STATUS_IF_ERROR(mMapper.createOrUpdatePatch(
624 aidlSources, aidlSinks, &newAidlPatchId, &cleanups));
625 mMapper.updateFwkPatch(aidlPatchId, newAidlPatchId);
626 } else {
627 RETURN_STATUS_IF_ERROR(mMapper.createOrUpdatePatch(
628 aidlSources, aidlSinks, &aidlHalPatchId, &cleanups));
629 }
630 } else {
631 RETURN_STATUS_IF_ERROR(mMapper.createOrUpdatePatch(
632 aidlSources, aidlSinks, &aidlPatchId, &cleanups));
633 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800634 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700635 *patch = static_cast<audio_patch_handle_t>(aidlPatchId);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800636 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000637 return OK;
638}
639
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800640status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800641 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000642 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700643 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800644 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
645 if (patch == AUDIO_PATCH_HANDLE_NONE) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800646 return BAD_VALUE;
647 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700648 std::lock_guard l(mLock);
Mikhail Naganov6b5da722024-03-14 12:59:32 -0700649 // Check for patches that only exist for the framework, or have different HAL patch ID.
650 int32_t aidlPatchId = static_cast<int32_t>(patch);
651 if (int32_t aidlHalPatchId = mMapper.findFwkPatch(aidlPatchId); aidlHalPatchId != 0) {
652 if (aidlHalPatchId == aidlPatchId) {
653 // This patch was previously released by the HAL, just need to finish its removal.
654 mMapper.eraseFwkPatch(aidlPatchId);
655 return OK;
656 } else {
657 // This patch has a HAL patch ID which is different
658 aidlPatchId = aidlHalPatchId;
659 }
660 }
661 RETURN_STATUS_IF_ERROR(mMapper.releaseAudioPatch(aidlPatchId));
Shunkai Yao51202502022-12-12 06:11:46 +0000662 return OK;
663}
664
Mikhail Naganove93a0862023-03-15 17:06:59 -0700665status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700666 if (port == nullptr) {
667 return BAD_VALUE;
668 }
669 audio_port_v7 portV7;
670 audio_populate_audio_port_v7(port, &portV7);
671 RETURN_STATUS_IF_ERROR(getAudioPort(&portV7));
672 return audio_populate_audio_port(&portV7, port) ? OK : BAD_VALUE;
673}
674
675status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
676 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
677 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700678 if (mModule == nullptr) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700679 if (port == nullptr) {
680 return BAD_VALUE;
681 }
682 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
683 ::aidl::android::AudioPortDirection::INPUT;
684 auto aidlPort = VALUE_OR_RETURN_STATUS(
685 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
686 if (aidlPort.ext.getTag() != AudioPortExt::device) {
687 ALOGE("%s: provided port is not a device port (module %s): %s",
688 __func__, mInstance.c_str(), aidlPort.toString().c_str());
689 return BAD_VALUE;
690 }
691 const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
692 // It seems that we don't have to call HAL since all valid ports have been added either
693 // during initialization, or while handling connection of an external device.
Mikhail Naganove93a0862023-03-15 17:06:59 -0700694 const int32_t fwkId = aidlPort.id;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700695 {
696 std::lock_guard l(mLock);
697 RETURN_STATUS_IF_ERROR(mMapper.getAudioPortCached(matchDevice, &aidlPort));
698 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700699 aidlPort.id = fwkId;
700 *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
701 aidlPort, isInput));
702 return OK;
703}
704
jiabin12537fc2023-10-12 17:56:08 +0000705status_t DeviceHalAidl::getAudioMixPort(const struct audio_port_v7 *devicePort,
706 struct audio_port_v7 *mixPort) {
707 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700708 TIME_CHECK();
709 if (mModule == nullptr) return NO_INIT;
710 if (devicePort == nullptr || mixPort == nullptr ||
711 devicePort->type != AUDIO_PORT_TYPE_DEVICE || mixPort->type != AUDIO_PORT_TYPE_MIX) {
jiabin12537fc2023-10-12 17:56:08 +0000712 return BAD_VALUE;
713 }
714 const int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
715 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(mixPort->ext.mix.handle));
jiabin12537fc2023-10-12 17:56:08 +0000716 AudioPort port;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700717 {
718 std::lock_guard l(mLock);
719 RETURN_STATUS_IF_ERROR(mMapper.getAudioMixPort(aidlHandle, &port));
jiabin12537fc2023-10-12 17:56:08 +0000720 }
721 const bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
722 mixPort->role, mixPort->type)) == ::aidl::android::AudioPortDirection::INPUT;
723 *mixPort = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
724 port, isInput));
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700725 return OK;
jiabin12537fc2023-10-12 17:56:08 +0000726}
727
Mikhail Naganove93a0862023-03-15 17:06:59 -0700728status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
729 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
730 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700731 if (mModule == nullptr) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700732 if (config == nullptr) {
733 return BAD_VALUE;
734 }
735 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
736 config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
737 AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
738 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
739 *config, isInput, 0 /*portId*/));
740 AudioPortConfig portConfig;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700741 std::lock_guard l(mLock);
Mikhail Naganovca92a5c2023-12-07 14:00:48 -0800742 return mMapper.setPortConfig(requestedPortConfig, std::set<int32_t>(), &portConfig);
Shunkai Yao51202502022-12-12 06:11:46 +0000743}
744
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800745MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700746 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
747 TIME_CHECK();
748 if (!mModule) return {};
749 std::lock_guard l(mLock);
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800750 if (mMicrophones.status == Microphones::Status::UNKNOWN) {
751 TIME_CHECK();
752 std::vector<MicrophoneInfo> aidlInfo;
753 status_t status = statusTFromBinderStatus(mModule->getMicrophones(&aidlInfo));
754 if (status == OK) {
755 mMicrophones.status = Microphones::Status::QUERIED;
756 mMicrophones.info = std::move(aidlInfo);
757 } else if (status == INVALID_OPERATION) {
758 mMicrophones.status = Microphones::Status::NOT_SUPPORTED;
759 } else {
760 ALOGE("%s: Unexpected status from 'IModule.getMicrophones': %d", __func__, status);
761 return {};
762 }
763 }
764 if (mMicrophones.status == Microphones::Status::QUERIED) {
765 return &mMicrophones.info;
766 }
767 return {}; // NOT_SUPPORTED
768}
769
Shunkai Yao51202502022-12-12 06:11:46 +0000770status_t DeviceHalAidl::getMicrophones(
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800771 std::vector<audio_microphone_characteristic_t>* microphones) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700772 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
773 TIME_CHECK();
774 if (mModule == nullptr) return NO_INIT;
775 if (microphones == nullptr) {
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800776 return BAD_VALUE;
777 }
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800778 auto staticInfo = getMicrophoneInfo();
779 if (!staticInfo) return INVALID_OPERATION;
780 std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
781 emptyDynamicInfo.reserve(staticInfo->size());
782 std::transform(staticInfo->begin(), staticInfo->end(), std::back_inserter(emptyDynamicInfo),
783 [](const auto& info) { return MicrophoneDynamicInfo{ .id = info.id }; });
784 *microphones = VALUE_OR_RETURN_STATUS(
785 ::aidl::android::convertContainers<std::vector<audio_microphone_characteristic_t>>(
786 *staticInfo, emptyDynamicInfo,
787 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t)
788 );
Shunkai Yao51202502022-12-12 06:11:46 +0000789 return OK;
790}
791
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700792status_t DeviceHalAidl::addDeviceEffect(
793 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700794 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700795 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700796 if (mModule == nullptr) return NO_INIT;
797 if (device == nullptr || effect == nullptr) {
Shunkai Yao51202502022-12-12 06:11:46 +0000798 return BAD_VALUE;
799 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700800 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
801 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
802 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
803 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
804 *device, isInput, 0));
805 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
806 ALOGE("%s: provided port config is not a device port config: %s",
807 __func__, requestedPortConfig.toString().c_str());
808 return BAD_VALUE;
809 }
810 AudioPortConfig devicePortConfig;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700811 Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
812 {
813 std::lock_guard l(mLock);
Mikhail Naganovca92a5c2023-12-07 14:00:48 -0800814 RETURN_STATUS_IF_ERROR(mMapper.setPortConfig(
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700815 requestedPortConfig, {} /*destinationPortIds*/, &devicePortConfig, &cleanups));
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700816 }
817 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
818 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->addDeviceEffect(
819 devicePortConfig.id, aidlEffect->getIEffect())));
820 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000821 return OK;
822}
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700823status_t DeviceHalAidl::removeDeviceEffect(
824 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700825 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700826 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700827 if (mModule == nullptr) return NO_INIT;
828 if (device == nullptr || effect == nullptr) {
Shunkai Yao51202502022-12-12 06:11:46 +0000829 return BAD_VALUE;
830 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700831 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
832 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
833 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
834 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
835 *device, isInput, 0));
836 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
837 ALOGE("%s: provided port config is not a device port config: %s",
838 __func__, requestedPortConfig.toString().c_str());
839 return BAD_VALUE;
840 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700841 AudioPortConfig devicePortConfig;
842 {
843 std::lock_guard l(mLock);
844 RETURN_STATUS_IF_ERROR(mMapper.findPortConfig(
845 requestedPortConfig.ext.get<AudioPortExt::Tag::device>().device,
846 &devicePortConfig));
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700847 }
848 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
849 return statusTFromBinderStatus(mModule->removeDeviceEffect(
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700850 devicePortConfig.id, aidlEffect->getIEffect()));
Shunkai Yao51202502022-12-12 06:11:46 +0000851}
852
853status_t DeviceHalAidl::getMmapPolicyInfos(
David Li9cf5e622023-03-21 00:51:10 +0800854 media::audio::common::AudioMMapPolicyType policyType,
855 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700856 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000857 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700858 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov25bc9a22023-04-21 18:48:16 -0700859 AudioMMapPolicyType mmapPolicyType = VALUE_OR_RETURN_STATUS(
860 cpp2ndk_AudioMMapPolicyType(policyType));
David Li9cf5e622023-03-21 00:51:10 +0800861
862 std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
863
864 if (status_t status = statusTFromBinderStatus(
865 mModule->getMmapPolicyInfos(mmapPolicyType, &mmapPolicyInfos)); status != OK) {
866 return status;
867 }
868
869 *policyInfos = VALUE_OR_RETURN_STATUS(
870 convertContainer<std::vector<media::audio::common::AudioMMapPolicyInfo>>(
871 mmapPolicyInfos, ndk2cpp_AudioMMapPolicyInfo));
Shunkai Yao51202502022-12-12 06:11:46 +0000872 return OK;
873}
874
875int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700876 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000877 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700878 if (mModule == nullptr) return NO_INIT;
David Li9cf5e622023-03-21 00:51:10 +0800879 int32_t mixerBurstCount = 0;
880 if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
881 return mixerBurstCount;
882 }
883 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000884}
885
886int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
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;
David Li9cf5e622023-03-21 00:51:10 +0800890 int32_t hardwareBurstMinUsec = 0;
891 if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
892 return hardwareBurstMinUsec;
893 }
894 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000895}
896
897error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700898 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000899 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700900 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700901 int32_t aidlHwAvSync;
902 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
903 return VALUE_OR_RETURN_STATUS(
904 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +0000905}
906
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000907status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
908 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700909 if (mModule == nullptr) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000910 return mModule->dump(fd, Args(args).args(), args.size());
David Li9cf5e622023-03-21 00:51:10 +0800911}
Shunkai Yao51202502022-12-12 06:11:46 +0000912
Eric Laurent7af6ee72023-06-29 11:44:54 +0200913status_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700914 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000915 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700916 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700917 if (supports == nullptr) {
918 return BAD_VALUE;
919 }
920 return statusTFromBinderStatus(mModule->supportsVariableLatency(supports));
Shunkai Yao51202502022-12-12 06:11:46 +0000921}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000922
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100923status_t DeviceHalAidl::getSoundDoseInterface(const std::string& module,
924 ::ndk::SpAIBinder* soundDoseBinder) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700925 if (soundDoseBinder == nullptr) {
926 return BAD_VALUE;
927 }
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100928 if (mSoundDose == nullptr) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700929 ALOGE("%s failed to retrieve the sound dose interface for module %s",
930 __func__, module.c_str());
931 return BAD_VALUE;
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100932 }
Vlad Popae1f33902023-10-30 19:48:25 -0700933
934 if (mSoundDose == nullptr) {
935 ALOGE("%s failed to return the sound dose interface for module %s: not implemented",
936 __func__,
937 module.c_str());
938 return NO_INIT;
939 }
940
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100941 *soundDoseBinder = mSoundDose->asBinder();
942 ALOGI("%s using audio AIDL HAL sound dose interface", __func__);
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100943 return OK;
944}
jiabin872de702023-04-27 22:04:31 +0000945
946status_t DeviceHalAidl::prepareToDisconnectExternalDevice(const struct audio_port_v7* port) {
jiabin62750c22023-12-21 22:06:07 +0000947 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
948 TIME_CHECK();
949 if (mModule == nullptr) return NO_INIT;
950 if (port == nullptr) {
951 return BAD_VALUE;
952 }
953 const bool isInput = VALUE_OR_RETURN_STATUS(
954 ::aidl::android::portDirection(port->role, port->type)) ==
955 ::aidl::android::AudioPortDirection::INPUT;
956 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
957 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
958 if (aidlPort.ext.getTag() != AudioPortExt::device) {
959 ALOGE("%s: provided port is not a device port (module %s): %s",
960 __func__, mInstance.c_str(), aidlPort.toString().c_str());
961 return BAD_VALUE;
962 }
963 status_t status = NO_ERROR;
964 {
965 std::lock_guard l(mLock);
966 status = mMapper.prepareToDisconnectExternalDevice(aidlPort);
967 }
968 if (status == UNKNOWN_TRANSACTION) {
969 // If there is not AIDL API defined for `prepareToDisconnectExternalDevice`.
970 // Call `setConnectedState` instead.
971 RETURN_STATUS_IF_ERROR(setConnectedState(port, false /*connected*/));
972 std::lock_guard l(mLock);
973 mDeviceDisconnectionNotified.insert(port->id);
974 // Return that there was no error as otherwise the disconnection procedure will not be
975 // considered complete for upper layers, and 'setConnectedState' will not be called again
976 return OK;
977 } else {
978 return status;
979 }
jiabin872de702023-04-27 22:04:31 +0000980}
981
Mikhail Naganove93a0862023-03-15 17:06:59 -0700982status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
Mikhail Naganovae9063d2023-11-07 16:43:51 -0800983 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700984 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700985 if (mModule == nullptr) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700986 if (port == nullptr) {
987 return BAD_VALUE;
988 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700989 if (!connected) {
990 std::lock_guard l(mLock);
991 if (mDeviceDisconnectionNotified.erase(port->id) > 0) {
992 // For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
jiabin62750c22023-12-21 22:06:07 +0000993 // and then call `setConnectedState`. If `prepareToDisconnectExternalDevice` doesn't
994 // exit, `setConnectedState` will be called when calling
995 // `prepareToDisconnectExternalDevice`. Do not call to the HAL if previous call is
996 // successful. Also remove the cache here to avoid a large cache after a long run.
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700997 return OK;
998 }
jiabin872de702023-04-27 22:04:31 +0000999 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001000 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
1001 ::aidl::android::AudioPortDirection::INPUT;
1002 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
1003 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
1004 if (aidlPort.ext.getTag() != AudioPortExt::device) {
1005 ALOGE("%s: provided port is not a device port (module %s): %s",
1006 __func__, mInstance.c_str(), aidlPort.toString().c_str());
1007 return BAD_VALUE;
1008 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -07001009 std::lock_guard l(mLock);
1010 return mMapper.setDevicePortConnectedState(aidlPort, connected);
Mikhail Naganove93a0862023-03-15 17:06:59 -07001011}
1012
1013status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
1014 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -07001015 if (mModule == nullptr) return NO_INIT;
1016 {
1017 std::lock_guard l(mLock);
Mikhail Naganov6b5da722024-03-14 12:59:32 -07001018 mMapper.resetUnusedPatchesAndPortConfigs();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -07001019 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001020 ModuleDebug debug{ .simulateDeviceConnections = enabled };
1021 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
1022 // This is important to log as it affects HAL behavior.
1023 if (status == OK) {
1024 ALOGI("%s: set enabled: %d", __func__, enabled);
1025 } else {
1026 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
1027 }
1028 return status;
1029}
1030
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001031status_t DeviceHalAidl::filterAndRetrieveBtA2dpParameters(
1032 AudioParameter &keys, AudioParameter *result) {
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001033 if (String8 key = String8(AudioParameter::keyReconfigA2dpSupported); keys.containsKey(key)) {
1034 keys.remove(key);
David Lia7761ed2023-11-03 17:22:07 +00001035 if (mBluetoothA2dp != nullptr) {
1036 bool supports;
1037 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1038 mBluetoothA2dp->supportsOffloadReconfiguration(&supports)));
1039 result->addInt(key, supports ? 1 : 0);
1040 } else {
1041 ALOGI("%s: no IBluetoothA2dp on %s", __func__, mInstance.c_str());
1042 result->addInt(key, 0);
1043 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001044 }
1045 return OK;
1046}
1047
Eric Laurent7e3c0832023-11-30 15:04:50 +01001048status_t DeviceHalAidl::filterAndRetrieveBtLeParameters(
1049 AudioParameter &keys, AudioParameter *result) {
1050 if (String8 key = String8(AudioParameter::keyReconfigLeSupported); keys.containsKey(key)) {
1051 keys.remove(key);
1052 if (mBluetoothLe != nullptr) {
1053 bool supports;
1054 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1055 mBluetoothLe->supportsOffloadReconfiguration(&supports)));
1056 result->addInt(key, supports ? 1 : 0);
1057 } else {
1058 ALOGI("%s: no mBluetoothLe on %s", __func__, mInstance.c_str());
1059 result->addInt(key, 0);
1060 }
1061 }
1062 return OK;
1063}
1064
Mikhail Naganovccc82112023-04-27 18:14:15 -07001065status_t DeviceHalAidl::filterAndUpdateBtA2dpParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001066 std::optional<bool> a2dpEnabled;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001067 std::optional<std::vector<VendorParameter>> reconfigureOffload;
Mikhail Naganovccc82112023-04-27 18:14:15 -07001068 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1069 parameters, String8(AudioParameter::keyBtA2dpSuspended),
1070 [&a2dpEnabled](const String8& trueOrFalse) {
1071 if (trueOrFalse == AudioParameter::valueTrue) {
1072 a2dpEnabled = false; // 'suspended' == true
1073 return OK;
1074 } else if (trueOrFalse == AudioParameter::valueFalse) {
1075 a2dpEnabled = true; // 'suspended' == false
1076 return OK;
1077 }
1078 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1079 AudioParameter::keyBtA2dpSuspended, trueOrFalse.c_str());
1080 return BAD_VALUE;
1081 }));
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001082 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1083 parameters, String8(AudioParameter::keyReconfigA2dp),
1084 [&](const String8& value) -> status_t {
Mikhail Naganove5011002024-01-26 10:57:19 -08001085 std::vector<VendorParameter> result;
1086 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1087 mVendorExt->parseBluetoothA2dpReconfigureOffload(
1088 std::string(value.c_str()), &result)));
1089 reconfigureOffload = std::move(result);
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001090 return OK;
1091 }));
Mikhail Naganovccc82112023-04-27 18:14:15 -07001092 if (mBluetoothA2dp != nullptr && a2dpEnabled.has_value()) {
1093 return statusTFromBinderStatus(mBluetoothA2dp->setEnabled(a2dpEnabled.value()));
1094 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001095 if (mBluetoothA2dp != nullptr && reconfigureOffload.has_value()) {
1096 return statusTFromBinderStatus(mBluetoothA2dp->reconfigureOffload(
1097 reconfigureOffload.value()));
1098 }
Mikhail Naganovccc82112023-04-27 18:14:15 -07001099 return OK;
1100}
1101
1102status_t DeviceHalAidl::filterAndUpdateBtHfpParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001103 IBluetooth::HfpConfig hfpConfig;
1104 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1105 parameters, String8(AudioParameter::keyBtHfpEnable),
1106 [&hfpConfig](const String8& trueOrFalse) {
1107 if (trueOrFalse == AudioParameter::valueTrue) {
1108 hfpConfig.isEnabled = Boolean{ .value = true };
1109 return OK;
1110 } else if (trueOrFalse == AudioParameter::valueFalse) {
1111 hfpConfig.isEnabled = Boolean{ .value = false };
1112 return OK;
1113 }
1114 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1115 AudioParameter::keyBtHfpEnable, trueOrFalse.c_str());
1116 return BAD_VALUE;
1117 }));
1118 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1119 parameters, String8(AudioParameter::keyBtHfpSamplingRate),
1120 [&hfpConfig](int sampleRate) {
1121 return sampleRate > 0 ?
1122 hfpConfig.sampleRate = Int{ .value = sampleRate }, OK : BAD_VALUE;
1123 }));
1124 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1125 parameters, String8(AudioParameter::keyBtHfpVolume),
1126 [&hfpConfig](int volume0to15) {
1127 if (volume0to15 >= 0 && volume0to15 <= 15) {
1128 hfpConfig.volume = Float{ .value = volume0to15 / 15.0f };
1129 return OK;
1130 }
1131 return BAD_VALUE;
1132 }));
1133 if (mBluetooth != nullptr && hfpConfig != IBluetooth::HfpConfig{}) {
1134 IBluetooth::HfpConfig newHfpConfig;
1135 return statusTFromBinderStatus(mBluetooth->setHfpConfig(hfpConfig, &newHfpConfig));
1136 }
1137 return OK;
1138}
1139
1140status_t DeviceHalAidl::filterAndUpdateBtLeParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001141 std::optional<bool> leEnabled;
Eric Laurent7e3c0832023-11-30 15:04:50 +01001142 std::optional<std::vector<VendorParameter>> reconfigureOffload;
Mikhail Naganovccc82112023-04-27 18:14:15 -07001143 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1144 parameters, String8(AudioParameter::keyBtLeSuspended),
1145 [&leEnabled](const String8& trueOrFalse) {
1146 if (trueOrFalse == AudioParameter::valueTrue) {
1147 leEnabled = false; // 'suspended' == true
1148 return OK;
1149 } else if (trueOrFalse == AudioParameter::valueFalse) {
1150 leEnabled = true; // 'suspended' == false
1151 return OK;
1152 }
1153 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1154 AudioParameter::keyBtLeSuspended, trueOrFalse.c_str());
1155 return BAD_VALUE;
1156 }));
Eric Laurent7e3c0832023-11-30 15:04:50 +01001157 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1158 parameters, String8(AudioParameter::keyReconfigLe),
1159 [&](const String8& value) -> status_t {
1160 if (mVendorExt != nullptr) {
1161 std::vector<VendorParameter> result;
1162 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1163 mVendorExt->parseBluetoothLeReconfigureOffload(
1164 std::string(value.c_str()), &result)));
1165 reconfigureOffload = std::move(result);
1166 } else {
1167 reconfigureOffload = std::vector<VendorParameter>();
1168 }
1169 return OK;
1170 }));
Mikhail Naganovccc82112023-04-27 18:14:15 -07001171 if (mBluetoothLe != nullptr && leEnabled.has_value()) {
1172 return statusTFromBinderStatus(mBluetoothLe->setEnabled(leEnabled.value()));
1173 }
Eric Laurent7e3c0832023-11-30 15:04:50 +01001174 if (mBluetoothLe != nullptr && reconfigureOffload.has_value()) {
1175 return statusTFromBinderStatus(mBluetoothLe->reconfigureOffload(
1176 reconfigureOffload.value()));
1177 }
Mikhail Naganovccc82112023-04-27 18:14:15 -07001178 return OK;
1179}
1180
1181status_t DeviceHalAidl::filterAndUpdateBtScoParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001182 IBluetooth::ScoConfig scoConfig;
1183 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1184 parameters, String8(AudioParameter::keyBtSco),
1185 [&scoConfig](const String8& onOrOff) {
1186 if (onOrOff == AudioParameter::valueOn) {
1187 scoConfig.isEnabled = Boolean{ .value = true };
1188 return OK;
1189 } else if (onOrOff == AudioParameter::valueOff) {
1190 scoConfig.isEnabled = Boolean{ .value = false };
1191 return OK;
1192 }
1193 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1194 AudioParameter::keyBtSco, onOrOff.c_str());
1195 return BAD_VALUE;
1196 }));
1197 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1198 parameters, String8(AudioParameter::keyBtScoHeadsetName),
1199 [&scoConfig](const String8& name) {
1200 scoConfig.debugName = name;
1201 return OK;
1202 }));
1203 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1204 parameters, String8(AudioParameter::keyBtNrec),
1205 [&scoConfig](const String8& onOrOff) {
1206 if (onOrOff == AudioParameter::valueOn) {
1207 scoConfig.isNrecEnabled = Boolean{ .value = true };
1208 return OK;
1209 } else if (onOrOff == AudioParameter::valueOff) {
1210 scoConfig.isNrecEnabled = Boolean{ .value = false };
1211 return OK;
1212 }
1213 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1214 AudioParameter::keyBtNrec, onOrOff.c_str());
1215 return BAD_VALUE;
1216 }));
1217 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1218 parameters, String8(AudioParameter::keyBtScoWb),
1219 [&scoConfig](const String8& onOrOff) {
1220 if (onOrOff == AudioParameter::valueOn) {
1221 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO_WB;
1222 return OK;
1223 } else if (onOrOff == AudioParameter::valueOff) {
1224 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO;
1225 return OK;
1226 }
1227 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1228 AudioParameter::keyBtScoWb, onOrOff.c_str());
1229 return BAD_VALUE;
1230 }));
1231 if (mBluetooth != nullptr && scoConfig != IBluetooth::ScoConfig{}) {
1232 IBluetooth::ScoConfig newScoConfig;
1233 return statusTFromBinderStatus(mBluetooth->setScoConfig(scoConfig, &newScoConfig));
1234 }
1235 return OK;
1236}
1237
Mikhail Naganove92c34b2023-05-31 14:24:48 -07001238status_t DeviceHalAidl::filterAndUpdateScreenParameters(AudioParameter &parameters) {
Mikhail Naganove92c34b2023-05-31 14:24:48 -07001239 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1240 parameters, String8(AudioParameter::keyScreenState),
1241 [&](const String8& onOrOff) -> status_t {
1242 std::optional<bool> isTurnedOn;
1243 if (onOrOff == AudioParameter::valueOn) {
1244 isTurnedOn = true;
1245 } else if (onOrOff == AudioParameter::valueOff) {
1246 isTurnedOn = false;
1247 }
1248 if (!isTurnedOn.has_value()) {
1249 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1250 AudioParameter::keyScreenState, onOrOff.c_str());
1251 return BAD_VALUE;
1252 }
1253 return statusTFromBinderStatus(
1254 mModule->updateScreenState(isTurnedOn.value()));
1255 }));
1256 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1257 parameters, String8(AudioParameter::keyScreenRotation),
1258 [&](int rotationDegrees) -> status_t {
1259 IModule::ScreenRotation rotation;
1260 switch (rotationDegrees) {
1261 case 0: rotation = IModule::ScreenRotation::DEG_0; break;
1262 case 90: rotation = IModule::ScreenRotation::DEG_90; break;
1263 case 180: rotation = IModule::ScreenRotation::DEG_180; break;
1264 case 270: rotation = IModule::ScreenRotation::DEG_270; break;
1265 default:
1266 ALOGE("setParameters: parameter key \"%s\" has invalid value %d",
1267 AudioParameter::keyScreenRotation, rotationDegrees);
1268 return BAD_VALUE;
1269 }
1270 return statusTFromBinderStatus(mModule->updateScreenRotation(rotation));
1271 }));
1272 return OK;
1273}
1274
Mikhail Naganovb9a81312023-07-18 13:55:34 -07001275status_t DeviceHalAidl::filterAndUpdateTelephonyParameters(AudioParameter &parameters) {
Mikhail Naganovb9a81312023-07-18 13:55:34 -07001276 using TtyMode = ITelephony::TelecomConfig::TtyMode;
1277 ITelephony::TelecomConfig telConfig;
1278 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1279 parameters, String8(AudioParameter::keyTtyMode),
1280 [&telConfig](const String8& mode) {
1281 if (mode == AudioParameter::valueTtyModeOff) {
1282 telConfig.ttyMode = TtyMode::OFF;
1283 return OK;
1284 } else if (mode == AudioParameter::valueTtyModeFull) {
1285 telConfig.ttyMode = TtyMode::FULL;
1286 return OK;
1287 } else if (mode == AudioParameter::valueTtyModeHco) {
1288 telConfig.ttyMode = TtyMode::HCO;
1289 return OK;
1290 } else if (mode == AudioParameter::valueTtyModeVco) {
1291 telConfig.ttyMode = TtyMode::VCO;
1292 return OK;
1293 }
1294 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1295 AudioParameter::keyTtyMode, mode.c_str());
1296 return BAD_VALUE;
1297 }));
1298 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1299 parameters, String8(AudioParameter::keyHacSetting),
1300 [&telConfig](const String8& onOrOff) {
1301 if (onOrOff == AudioParameter::valueHacOn) {
1302 telConfig.isHacEnabled = Boolean{ .value = true };
1303 return OK;
1304 } else if (onOrOff == AudioParameter::valueHacOff) {
1305 telConfig.isHacEnabled = Boolean{ .value = false };
1306 return OK;
1307 }
1308 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1309 AudioParameter::keyHacSetting, onOrOff.c_str());
1310 return BAD_VALUE;
1311 }));
1312 if (mTelephony != nullptr && telConfig != ITelephony::TelecomConfig{}) {
1313 ITelephony::TelecomConfig newTelConfig;
1314 return statusTFromBinderStatus(
1315 mTelephony->setTelecomConfig(telConfig, &newTelConfig));
1316 }
1317 return OK;
1318}
1319
Mikhail Naganovdfd594e2023-02-08 16:59:41 -08001320void DeviceHalAidl::clearCallbacks(void* cookie) {
1321 std::lock_guard l(mLock);
1322 mCallbacks.erase(cookie);
1323}
1324
1325sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1326 return getCallbackImpl(cookie, &Callbacks::out);
1327}
1328
1329void DeviceHalAidl::setStreamOutCallback(
1330 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1331 setCallbackImpl(cookie, &Callbacks::out, cb);
1332}
1333
1334sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1335 void* cookie) {
1336 return getCallbackImpl(cookie, &Callbacks::event);
1337}
1338
1339void DeviceHalAidl::setStreamOutEventCallback(
1340 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1341 setCallbackImpl(cookie, &Callbacks::event, cb);
1342}
1343
1344sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1345 void* cookie) {
1346 return getCallbackImpl(cookie, &Callbacks::latency);
1347}
1348
1349void DeviceHalAidl::setStreamOutLatencyModeCallback(
1350 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1351 setCallbackImpl(cookie, &Callbacks::latency, cb);
1352}
1353
1354template<class C>
1355sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1356 std::lock_guard l(mLock);
1357 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1358 return ((it->second).*field).promote();
1359 }
1360 return nullptr;
1361}
1362template<class C>
1363void DeviceHalAidl::setCallbackImpl(
1364 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1365 std::lock_guard l(mLock);
1366 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1367 (it->second).*field = cb;
1368 }
1369}
1370
Mikhail Naganov31d46652023-01-10 18:29:25 +00001371} // namespace android