blob: 1d8fec07b4779b435768a146494434447a6e083f [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 }
270 *values = result.toString();
271 return parseAndGetVendorParameters(mVendorExt, mModule, parameterKeys, values);
Shunkai Yao51202502022-12-12 06:11:46 +0000272}
273
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800274status_t DeviceHalAidl::getInputBufferSize(const struct audio_config* config, size_t* size) {
275 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800276 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700277 if (mModule == nullptr) return NO_INIT;
278 if (config == nullptr || size == nullptr) {
279 return BAD_VALUE;
280 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800281 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
282 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
283 AudioDevice aidlDevice;
284 aidlDevice.type.type = AudioDeviceType::IN_DEFAULT;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800285 AudioSource aidlSource = AudioSource::DEFAULT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800286 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
287 AudioPortConfig mixPortConfig;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700288 Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700289 AudioPatch aidlPatch;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700290 {
291 std::lock_guard l(mLock);
292 RETURN_STATUS_IF_ERROR(mMapper.prepareToOpenStream(
293 0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
294 &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
295 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800296 *size = aidlConfig.frameCount *
297 getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
298 // Do not disarm cleanups to release temporary port configs.
299 return OK;
300}
301
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800302namespace {
303
304class StreamCallbackBase {
305 protected:
306 explicit StreamCallbackBase(const sp<CallbackBroker>& broker) : mBroker(broker) {}
307 public:
308 void* getCookie() const { return mCookie; }
309 void setCookie(void* cookie) { mCookie = cookie; }
310 sp<CallbackBroker> getBroker() const {
311 if (void* cookie = mCookie; cookie != nullptr) return mBroker.promote();
312 return nullptr;
313 }
314 private:
315 const wp<CallbackBroker> mBroker;
316 std::atomic<void*> mCookie;
317};
318
319template<class C>
320class StreamCallbackBaseHelper {
321 protected:
322 explicit StreamCallbackBaseHelper(const StreamCallbackBase& base) : mBase(base) {}
323 sp<C> getCb(const sp<CallbackBroker>& broker, void* cookie);
324 using CbRef = const sp<C>&;
325 ndk::ScopedAStatus runCb(const std::function<void(CbRef cb)>& f) {
326 if (auto cb = getCb(mBase.getBroker(), mBase.getCookie()); cb != nullptr) f(cb);
327 return ndk::ScopedAStatus::ok();
328 }
329 private:
330 const StreamCallbackBase& mBase;
331};
332
333template<>
334sp<StreamOutHalInterfaceCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>::getCb(
335 const sp<CallbackBroker>& broker, void* cookie) {
336 if (broker != nullptr) return broker->getStreamOutCallback(cookie);
337 return nullptr;
338}
339
340template<>
341sp<StreamOutHalInterfaceEventCallback>
342StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::getCb(
343 const sp<CallbackBroker>& broker, void* cookie) {
344 if (broker != nullptr) return broker->getStreamOutEventCallback(cookie);
345 return nullptr;
346}
347
348template<>
349sp<StreamOutHalInterfaceLatencyModeCallback>
350StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::getCb(
351 const sp<CallbackBroker>& broker, void* cookie) {
352 if (broker != nullptr) return broker->getStreamOutLatencyModeCallback(cookie);
353 return nullptr;
354}
355
356/*
357Note on the callback ownership.
358
359In the Binder ownership model, the server implementation is kept alive
360as long as there is any client (proxy object) alive. This is done by
361incrementing the refcount of the server-side object by the Binder framework.
362When it detects that the last client is gone, it decrements the refcount back.
363
364Thus, it is not needed to keep any references to StreamCallback on our
365side (after we have sent an instance to the client), because we are
366the server-side. The callback object will be kept alive as long as the HAL server
367holds a strong ref to IStreamCallback proxy.
368*/
369
370class OutputStreamCallbackAidl : public StreamCallbackBase,
371 public StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>,
372 public ::aidl::android::hardware::audio::core::BnStreamCallback {
373 public:
374 explicit OutputStreamCallbackAidl(const sp<CallbackBroker>& broker)
375 : StreamCallbackBase(broker),
376 StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>(
377 *static_cast<StreamCallbackBase*>(this)) {}
378 ndk::ScopedAStatus onTransferReady() override {
379 return runCb([](CbRef cb) { cb->onWriteReady(); });
380 }
381 ndk::ScopedAStatus onError() override {
382 return runCb([](CbRef cb) { cb->onError(); });
383 }
384 ndk::ScopedAStatus onDrainReady() override {
385 return runCb([](CbRef cb) { cb->onDrainReady(); });
386 }
387};
388
389class OutputStreamEventCallbackAidl :
390 public StreamCallbackBase,
391 public StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>,
392 public StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>,
393 public ::aidl::android::hardware::audio::core::BnStreamOutEventCallback {
394 public:
395 explicit OutputStreamEventCallbackAidl(const sp<CallbackBroker>& broker)
396 : StreamCallbackBase(broker),
397 StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>(
398 *static_cast<StreamCallbackBase*>(this)),
399 StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>(
400 *static_cast<StreamCallbackBase*>(this)) {}
Ryan Prichard78c5e452024-02-08 16:16:57 -0800401 ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& halMetadata) override {
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800402 return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb(
403 [&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); });
404 }
405 ndk::ScopedAStatus onRecommendedLatencyModeChanged(
406 const std::vector<AudioLatencyMode>& in_modes) override {
407 auto halModes = VALUE_OR_FATAL(
408 ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
409 in_modes,
410 ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
411 return StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::runCb(
412 [&halModes](auto cb) { cb->onRecommendedLatencyModeChanged(halModes); });
413 }
414};
415
416} // namespace
417
Mikhail Naganov31d46652023-01-10 18:29:25 +0000418status_t DeviceHalAidl::openOutputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800419 audio_io_handle_t handle, audio_devices_t devices,
420 audio_output_flags_t flags, struct audio_config* config,
421 const char* address,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000422 sp<StreamOutHalInterface>* outStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800423 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700424 TIME_CHECK();
425 if (mModule == nullptr) return NO_INIT;
426 if (outStream == nullptr || config == nullptr) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000427 return BAD_VALUE;
428 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700429 constexpr bool isInput = false;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800430 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
431 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
432 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700433 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, isInput));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800434 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
435 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
436 int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
437 ::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
438 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
439 AudioPortConfig mixPortConfig;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700440 AudioPatch aidlPatch;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700441 Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
442 {
443 std::lock_guard l(mLock);
444 RETURN_STATUS_IF_ERROR(mMapper.prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
445 AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
446 &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
447 }
448 *config = VALUE_OR_RETURN_STATUS(
449 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(aidlConfig, isInput));
Mikhail Naganovca92a5c2023-12-07 14:00:48 -0800450 if (mixPortConfig.id == 0) return BAD_VALUE; // HAL suggests a different config.
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800451 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
452 args.portConfigId = mixPortConfig.id;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800453 const bool isOffload = isBitPositionFlagSet(
454 aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD);
455 std::shared_ptr<OutputStreamCallbackAidl> streamCb;
456 if (isOffload) {
457 streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
458 }
459 auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
460 if (isOffload) {
461 args.offloadInfo = aidlConfig.offloadInfo;
462 args.callback = streamCb;
463 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800464 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800465 args.eventCallback = eventCb;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800466 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
467 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800468 StreamContextAidl context(ret.desc, isOffload);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800469 if (!context.isValid()) {
470 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
471 __func__, ret.desc.toString().c_str());
472 return NO_INIT;
473 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700474 *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700475 std::move(ret.stream), mVendorExt, this /*callbackBroker*/);
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800476 void* cbCookie = (*outStream).get();
477 {
478 std::lock_guard l(mLock);
479 mCallbacks.emplace(cbCookie, Callbacks{});
Mikhail Naganov78f7f9a2023-11-16 15:49:23 -0800480 mMapper.addStream(*outStream, mixPortConfig.id, aidlPatch.id);
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800481 }
482 if (streamCb) streamCb->setCookie(cbCookie);
483 eventCb->setCookie(cbCookie);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800484 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000485 return OK;
486}
487
Mikhail Naganov31d46652023-01-10 18:29:25 +0000488status_t DeviceHalAidl::openInputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800489 audio_io_handle_t handle, audio_devices_t devices,
490 struct audio_config* config, audio_input_flags_t flags,
491 const char* address, audio_source_t source,
492 audio_devices_t outputDevice, const char* outputDeviceAddress,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000493 sp<StreamInHalInterface>* inStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800494 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700495 TIME_CHECK();
496 if (mModule == nullptr) return NO_INIT;
497 if (inStream == nullptr || config == nullptr) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000498 return BAD_VALUE;
499 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700500 constexpr bool isInput = true;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800501 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
502 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
503 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700504 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, isInput));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800505 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
506 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
507 int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
508 ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
509 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
510 AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
511 ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
512 AudioPortConfig mixPortConfig;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700513 AudioPatch aidlPatch;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700514 Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
515 {
516 std::lock_guard l(mLock);
517 RETURN_STATUS_IF_ERROR(mMapper.prepareToOpenStream(
518 aidlHandle, aidlDevice, aidlFlags, aidlSource,
519 &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
520 }
521 *config = VALUE_OR_RETURN_STATUS(
522 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(aidlConfig, isInput));
Mikhail Naganovca92a5c2023-12-07 14:00:48 -0800523 if (mixPortConfig.id == 0) return BAD_VALUE; // HAL suggests a different config.
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800524 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
525 args.portConfigId = mixPortConfig.id;
526 RecordTrackMetadata aidlTrackMetadata{
527 .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
528 if (outputDevice != AUDIO_DEVICE_NONE) {
529 aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
530 ::aidl::android::legacy2aidl_audio_device_AudioDevice(
531 outputDevice, outputDeviceAddress));
532 }
533 args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
534 args.bufferSizeFrames = aidlConfig.frameCount;
535 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
536 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800537 StreamContextAidl context(ret.desc, false /*isAsynchronous*/);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800538 if (!context.isValid()) {
539 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
540 __func__, ret.desc.toString().c_str());
541 return NO_INIT;
542 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700543 *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700544 std::move(ret.stream), mVendorExt, this /*micInfoProvider*/);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700545 {
546 std::lock_guard l(mLock);
Mikhail Naganov78f7f9a2023-11-16 15:49:23 -0800547 mMapper.addStream(*inStream, mixPortConfig.id, aidlPatch.id);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700548 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800549 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000550 return OK;
551}
552
553status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700554 if (supportsPatches == nullptr) {
555 return BAD_VALUE;
556 }
Shunkai Yao51202502022-12-12 06:11:46 +0000557 *supportsPatches = true;
558 return OK;
559}
560
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800561status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
562 const struct audio_port_config* sources,
563 unsigned int num_sinks,
564 const struct audio_port_config* sinks,
565 audio_patch_handle_t* patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800566 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000567 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700568 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800569 if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
570 sources == nullptr || sinks == nullptr || patch == nullptr) {
571 return BAD_VALUE;
572 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800573 // When the patch handle (*patch) is AUDIO_PATCH_HANDLE_NONE, it means
574 // the framework wants to create a new patch. The handle has to be generated
575 // by the HAL. Since handles generated this way can only be unique within
576 // a HAL module, the framework generates a globally unique handle, and maps
577 // it on the <HAL module, patch handle> pair.
578 // When the patch handle is set, it meant the framework intends to update
579 // an existing patch.
580 //
581 // This behavior corresponds to HAL module behavior, with the only difference
582 // that the HAL module uses `int32_t` for patch IDs. The following assert ensures
583 // that both the framework and the HAL use the same value for "no ID":
584 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700585 int32_t aidlPatchId = static_cast<int32_t>(*patch);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800586
587 // Upon conversion, mix port configs contain audio configuration, while
588 // device port configs contain device address. This data is used to find
589 // or create HAL configs.
590 std::vector<AudioPortConfig> aidlSources, aidlSinks;
591 for (unsigned int i = 0; i < num_sources; ++i) {
592 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
593 sources[i].role, sources[i].type)) ==
594 ::aidl::android::AudioPortDirection::INPUT;
595 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
596 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
597 sources[i], isInput, 0)));
598 }
599 for (unsigned int i = 0; i < num_sinks; ++i) {
600 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
601 sinks[i].role, sinks[i].type)) ==
602 ::aidl::android::AudioPortDirection::INPUT;
603 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
604 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
605 sinks[i], isInput, 0)));
606 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700607 Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
608 {
609 std::lock_guard l(mLock);
610 RETURN_STATUS_IF_ERROR(mMapper.createOrUpdatePatch(
611 aidlSources, aidlSinks, &aidlPatchId, &cleanups));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800612 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700613 *patch = static_cast<audio_patch_handle_t>(aidlPatchId);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800614 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000615 return OK;
616}
617
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800618status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800619 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000620 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700621 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800622 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
623 if (patch == AUDIO_PATCH_HANDLE_NONE) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800624 return BAD_VALUE;
625 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700626 std::lock_guard l(mLock);
627 RETURN_STATUS_IF_ERROR(mMapper.releaseAudioPatch(static_cast<int32_t>(patch)));
Shunkai Yao51202502022-12-12 06:11:46 +0000628 return OK;
629}
630
Mikhail Naganove93a0862023-03-15 17:06:59 -0700631status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700632 if (port == nullptr) {
633 return BAD_VALUE;
634 }
635 audio_port_v7 portV7;
636 audio_populate_audio_port_v7(port, &portV7);
637 RETURN_STATUS_IF_ERROR(getAudioPort(&portV7));
638 return audio_populate_audio_port(&portV7, port) ? OK : BAD_VALUE;
639}
640
641status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
642 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
643 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700644 if (mModule == nullptr) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700645 if (port == nullptr) {
646 return BAD_VALUE;
647 }
648 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
649 ::aidl::android::AudioPortDirection::INPUT;
650 auto aidlPort = VALUE_OR_RETURN_STATUS(
651 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
652 if (aidlPort.ext.getTag() != AudioPortExt::device) {
653 ALOGE("%s: provided port is not a device port (module %s): %s",
654 __func__, mInstance.c_str(), aidlPort.toString().c_str());
655 return BAD_VALUE;
656 }
657 const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
658 // It seems that we don't have to call HAL since all valid ports have been added either
659 // during initialization, or while handling connection of an external device.
Mikhail Naganove93a0862023-03-15 17:06:59 -0700660 const int32_t fwkId = aidlPort.id;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700661 {
662 std::lock_guard l(mLock);
663 RETURN_STATUS_IF_ERROR(mMapper.getAudioPortCached(matchDevice, &aidlPort));
664 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700665 aidlPort.id = fwkId;
666 *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
667 aidlPort, isInput));
668 return OK;
669}
670
jiabin12537fc2023-10-12 17:56:08 +0000671status_t DeviceHalAidl::getAudioMixPort(const struct audio_port_v7 *devicePort,
672 struct audio_port_v7 *mixPort) {
673 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700674 TIME_CHECK();
675 if (mModule == nullptr) return NO_INIT;
676 if (devicePort == nullptr || mixPort == nullptr ||
677 devicePort->type != AUDIO_PORT_TYPE_DEVICE || mixPort->type != AUDIO_PORT_TYPE_MIX) {
jiabin12537fc2023-10-12 17:56:08 +0000678 return BAD_VALUE;
679 }
680 const int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
681 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(mixPort->ext.mix.handle));
jiabin12537fc2023-10-12 17:56:08 +0000682 AudioPort port;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700683 {
684 std::lock_guard l(mLock);
685 RETURN_STATUS_IF_ERROR(mMapper.getAudioMixPort(aidlHandle, &port));
jiabin12537fc2023-10-12 17:56:08 +0000686 }
687 const bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
688 mixPort->role, mixPort->type)) == ::aidl::android::AudioPortDirection::INPUT;
689 *mixPort = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
690 port, isInput));
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700691 return OK;
jiabin12537fc2023-10-12 17:56:08 +0000692}
693
Mikhail Naganove93a0862023-03-15 17:06:59 -0700694status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
695 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
696 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700697 if (mModule == nullptr) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700698 if (config == nullptr) {
699 return BAD_VALUE;
700 }
701 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
702 config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
703 AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
704 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
705 *config, isInput, 0 /*portId*/));
706 AudioPortConfig portConfig;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700707 std::lock_guard l(mLock);
Mikhail Naganovca92a5c2023-12-07 14:00:48 -0800708 return mMapper.setPortConfig(requestedPortConfig, std::set<int32_t>(), &portConfig);
Shunkai Yao51202502022-12-12 06:11:46 +0000709}
710
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800711MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700712 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
713 TIME_CHECK();
714 if (!mModule) return {};
715 std::lock_guard l(mLock);
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800716 if (mMicrophones.status == Microphones::Status::UNKNOWN) {
717 TIME_CHECK();
718 std::vector<MicrophoneInfo> aidlInfo;
719 status_t status = statusTFromBinderStatus(mModule->getMicrophones(&aidlInfo));
720 if (status == OK) {
721 mMicrophones.status = Microphones::Status::QUERIED;
722 mMicrophones.info = std::move(aidlInfo);
723 } else if (status == INVALID_OPERATION) {
724 mMicrophones.status = Microphones::Status::NOT_SUPPORTED;
725 } else {
726 ALOGE("%s: Unexpected status from 'IModule.getMicrophones': %d", __func__, status);
727 return {};
728 }
729 }
730 if (mMicrophones.status == Microphones::Status::QUERIED) {
731 return &mMicrophones.info;
732 }
733 return {}; // NOT_SUPPORTED
734}
735
Shunkai Yao51202502022-12-12 06:11:46 +0000736status_t DeviceHalAidl::getMicrophones(
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800737 std::vector<audio_microphone_characteristic_t>* microphones) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700738 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
739 TIME_CHECK();
740 if (mModule == nullptr) return NO_INIT;
741 if (microphones == nullptr) {
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800742 return BAD_VALUE;
743 }
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800744 auto staticInfo = getMicrophoneInfo();
745 if (!staticInfo) return INVALID_OPERATION;
746 std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
747 emptyDynamicInfo.reserve(staticInfo->size());
748 std::transform(staticInfo->begin(), staticInfo->end(), std::back_inserter(emptyDynamicInfo),
749 [](const auto& info) { return MicrophoneDynamicInfo{ .id = info.id }; });
750 *microphones = VALUE_OR_RETURN_STATUS(
751 ::aidl::android::convertContainers<std::vector<audio_microphone_characteristic_t>>(
752 *staticInfo, emptyDynamicInfo,
753 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t)
754 );
Shunkai Yao51202502022-12-12 06:11:46 +0000755 return OK;
756}
757
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700758status_t DeviceHalAidl::addDeviceEffect(
759 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700760 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700761 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700762 if (mModule == nullptr) return NO_INIT;
763 if (device == nullptr || effect == nullptr) {
Shunkai Yao51202502022-12-12 06:11:46 +0000764 return BAD_VALUE;
765 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700766 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
767 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
768 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
769 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
770 *device, isInput, 0));
771 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
772 ALOGE("%s: provided port config is not a device port config: %s",
773 __func__, requestedPortConfig.toString().c_str());
774 return BAD_VALUE;
775 }
776 AudioPortConfig devicePortConfig;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700777 Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
778 {
779 std::lock_guard l(mLock);
Mikhail Naganovca92a5c2023-12-07 14:00:48 -0800780 RETURN_STATUS_IF_ERROR(mMapper.setPortConfig(
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700781 requestedPortConfig, {} /*destinationPortIds*/, &devicePortConfig, &cleanups));
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700782 }
783 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
784 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->addDeviceEffect(
785 devicePortConfig.id, aidlEffect->getIEffect())));
786 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000787 return OK;
788}
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700789status_t DeviceHalAidl::removeDeviceEffect(
790 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700791 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700792 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700793 if (mModule == nullptr) return NO_INIT;
794 if (device == nullptr || effect == nullptr) {
Shunkai Yao51202502022-12-12 06:11:46 +0000795 return BAD_VALUE;
796 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700797 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
798 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
799 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
800 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
801 *device, isInput, 0));
802 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
803 ALOGE("%s: provided port config is not a device port config: %s",
804 __func__, requestedPortConfig.toString().c_str());
805 return BAD_VALUE;
806 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700807 AudioPortConfig devicePortConfig;
808 {
809 std::lock_guard l(mLock);
810 RETURN_STATUS_IF_ERROR(mMapper.findPortConfig(
811 requestedPortConfig.ext.get<AudioPortExt::Tag::device>().device,
812 &devicePortConfig));
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700813 }
814 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
815 return statusTFromBinderStatus(mModule->removeDeviceEffect(
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700816 devicePortConfig.id, aidlEffect->getIEffect()));
Shunkai Yao51202502022-12-12 06:11:46 +0000817}
818
819status_t DeviceHalAidl::getMmapPolicyInfos(
David Li9cf5e622023-03-21 00:51:10 +0800820 media::audio::common::AudioMMapPolicyType policyType,
821 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700822 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000823 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700824 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov25bc9a22023-04-21 18:48:16 -0700825 AudioMMapPolicyType mmapPolicyType = VALUE_OR_RETURN_STATUS(
826 cpp2ndk_AudioMMapPolicyType(policyType));
David Li9cf5e622023-03-21 00:51:10 +0800827
828 std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
829
830 if (status_t status = statusTFromBinderStatus(
831 mModule->getMmapPolicyInfos(mmapPolicyType, &mmapPolicyInfos)); status != OK) {
832 return status;
833 }
834
835 *policyInfos = VALUE_OR_RETURN_STATUS(
836 convertContainer<std::vector<media::audio::common::AudioMMapPolicyInfo>>(
837 mmapPolicyInfos, ndk2cpp_AudioMMapPolicyInfo));
Shunkai Yao51202502022-12-12 06:11:46 +0000838 return OK;
839}
840
841int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700842 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000843 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700844 if (mModule == nullptr) return NO_INIT;
David Li9cf5e622023-03-21 00:51:10 +0800845 int32_t mixerBurstCount = 0;
846 if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
847 return mixerBurstCount;
848 }
849 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000850}
851
852int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700853 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000854 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700855 if (mModule == nullptr) return NO_INIT;
David Li9cf5e622023-03-21 00:51:10 +0800856 int32_t hardwareBurstMinUsec = 0;
857 if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
858 return hardwareBurstMinUsec;
859 }
860 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000861}
862
863error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700864 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000865 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700866 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700867 int32_t aidlHwAvSync;
868 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
869 return VALUE_OR_RETURN_STATUS(
870 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +0000871}
872
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000873status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
874 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700875 if (mModule == nullptr) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000876 return mModule->dump(fd, Args(args).args(), args.size());
David Li9cf5e622023-03-21 00:51:10 +0800877}
Shunkai Yao51202502022-12-12 06:11:46 +0000878
Eric Laurent7af6ee72023-06-29 11:44:54 +0200879status_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700880 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000881 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700882 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700883 if (supports == nullptr) {
884 return BAD_VALUE;
885 }
886 return statusTFromBinderStatus(mModule->supportsVariableLatency(supports));
Shunkai Yao51202502022-12-12 06:11:46 +0000887}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000888
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100889status_t DeviceHalAidl::getSoundDoseInterface(const std::string& module,
890 ::ndk::SpAIBinder* soundDoseBinder) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700891 if (soundDoseBinder == nullptr) {
892 return BAD_VALUE;
893 }
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100894 if (mSoundDose == nullptr) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700895 ALOGE("%s failed to retrieve the sound dose interface for module %s",
896 __func__, module.c_str());
897 return BAD_VALUE;
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100898 }
899 *soundDoseBinder = mSoundDose->asBinder();
900 ALOGI("%s using audio AIDL HAL sound dose interface", __func__);
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100901 return OK;
902}
jiabin872de702023-04-27 22:04:31 +0000903
904status_t DeviceHalAidl::prepareToDisconnectExternalDevice(const struct audio_port_v7* port) {
jiabin62750c22023-12-21 22:06:07 +0000905 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
906 TIME_CHECK();
907 if (mModule == nullptr) return NO_INIT;
908 if (port == nullptr) {
909 return BAD_VALUE;
910 }
911 const bool isInput = VALUE_OR_RETURN_STATUS(
912 ::aidl::android::portDirection(port->role, port->type)) ==
913 ::aidl::android::AudioPortDirection::INPUT;
914 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
915 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
916 if (aidlPort.ext.getTag() != AudioPortExt::device) {
917 ALOGE("%s: provided port is not a device port (module %s): %s",
918 __func__, mInstance.c_str(), aidlPort.toString().c_str());
919 return BAD_VALUE;
920 }
921 status_t status = NO_ERROR;
922 {
923 std::lock_guard l(mLock);
924 status = mMapper.prepareToDisconnectExternalDevice(aidlPort);
925 }
926 if (status == UNKNOWN_TRANSACTION) {
927 // If there is not AIDL API defined for `prepareToDisconnectExternalDevice`.
928 // Call `setConnectedState` instead.
929 RETURN_STATUS_IF_ERROR(setConnectedState(port, false /*connected*/));
930 std::lock_guard l(mLock);
931 mDeviceDisconnectionNotified.insert(port->id);
932 // Return that there was no error as otherwise the disconnection procedure will not be
933 // considered complete for upper layers, and 'setConnectedState' will not be called again
934 return OK;
935 } else {
936 return status;
937 }
jiabin872de702023-04-27 22:04:31 +0000938}
939
Mikhail Naganove93a0862023-03-15 17:06:59 -0700940status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
Mikhail Naganovae9063d2023-11-07 16:43:51 -0800941 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700942 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700943 if (mModule == nullptr) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700944 if (port == nullptr) {
945 return BAD_VALUE;
946 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700947 if (!connected) {
948 std::lock_guard l(mLock);
949 if (mDeviceDisconnectionNotified.erase(port->id) > 0) {
950 // For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
jiabin62750c22023-12-21 22:06:07 +0000951 // and then call `setConnectedState`. If `prepareToDisconnectExternalDevice` doesn't
952 // exit, `setConnectedState` will be called when calling
953 // `prepareToDisconnectExternalDevice`. Do not call to the HAL if previous call is
954 // successful. Also remove the cache here to avoid a large cache after a long run.
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700955 return OK;
956 }
jiabin872de702023-04-27 22:04:31 +0000957 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700958 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
959 ::aidl::android::AudioPortDirection::INPUT;
960 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
961 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
962 if (aidlPort.ext.getTag() != AudioPortExt::device) {
963 ALOGE("%s: provided port is not a device port (module %s): %s",
964 __func__, mInstance.c_str(), aidlPort.toString().c_str());
965 return BAD_VALUE;
966 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700967 std::lock_guard l(mLock);
968 return mMapper.setDevicePortConnectedState(aidlPort, connected);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700969}
970
971status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
972 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700973 if (mModule == nullptr) return NO_INIT;
974 {
975 std::lock_guard l(mLock);
Mikhail Naganov15520da2024-01-17 11:15:20 -0800976 mMapper.resetUnusedPatchesPortConfigsAndPorts();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700977 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700978 ModuleDebug debug{ .simulateDeviceConnections = enabled };
979 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
980 // This is important to log as it affects HAL behavior.
981 if (status == OK) {
982 ALOGI("%s: set enabled: %d", __func__, enabled);
983 } else {
984 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
985 }
986 return status;
987}
988
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700989status_t DeviceHalAidl::filterAndRetrieveBtA2dpParameters(
990 AudioParameter &keys, AudioParameter *result) {
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700991 if (String8 key = String8(AudioParameter::keyReconfigA2dpSupported); keys.containsKey(key)) {
992 keys.remove(key);
David Lia7761ed2023-11-03 17:22:07 +0000993 if (mBluetoothA2dp != nullptr) {
994 bool supports;
995 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
996 mBluetoothA2dp->supportsOffloadReconfiguration(&supports)));
997 result->addInt(key, supports ? 1 : 0);
998 } else {
999 ALOGI("%s: no IBluetoothA2dp on %s", __func__, mInstance.c_str());
1000 result->addInt(key, 0);
1001 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001002 }
1003 return OK;
1004}
1005
Mikhail Naganovccc82112023-04-27 18:14:15 -07001006status_t DeviceHalAidl::filterAndUpdateBtA2dpParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001007 std::optional<bool> a2dpEnabled;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001008 std::optional<std::vector<VendorParameter>> reconfigureOffload;
Mikhail Naganovccc82112023-04-27 18:14:15 -07001009 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1010 parameters, String8(AudioParameter::keyBtA2dpSuspended),
1011 [&a2dpEnabled](const String8& trueOrFalse) {
1012 if (trueOrFalse == AudioParameter::valueTrue) {
1013 a2dpEnabled = false; // 'suspended' == true
1014 return OK;
1015 } else if (trueOrFalse == AudioParameter::valueFalse) {
1016 a2dpEnabled = true; // 'suspended' == false
1017 return OK;
1018 }
1019 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1020 AudioParameter::keyBtA2dpSuspended, trueOrFalse.c_str());
1021 return BAD_VALUE;
1022 }));
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001023 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1024 parameters, String8(AudioParameter::keyReconfigA2dp),
1025 [&](const String8& value) -> status_t {
Mikhail Naganove5011002024-01-26 10:57:19 -08001026 std::vector<VendorParameter> result;
1027 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1028 mVendorExt->parseBluetoothA2dpReconfigureOffload(
1029 std::string(value.c_str()), &result)));
1030 reconfigureOffload = std::move(result);
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001031 return OK;
1032 }));
Mikhail Naganovccc82112023-04-27 18:14:15 -07001033 if (mBluetoothA2dp != nullptr && a2dpEnabled.has_value()) {
1034 return statusTFromBinderStatus(mBluetoothA2dp->setEnabled(a2dpEnabled.value()));
1035 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001036 if (mBluetoothA2dp != nullptr && reconfigureOffload.has_value()) {
1037 return statusTFromBinderStatus(mBluetoothA2dp->reconfigureOffload(
1038 reconfigureOffload.value()));
1039 }
Mikhail Naganovccc82112023-04-27 18:14:15 -07001040 return OK;
1041}
1042
1043status_t DeviceHalAidl::filterAndUpdateBtHfpParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001044 IBluetooth::HfpConfig hfpConfig;
1045 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1046 parameters, String8(AudioParameter::keyBtHfpEnable),
1047 [&hfpConfig](const String8& trueOrFalse) {
1048 if (trueOrFalse == AudioParameter::valueTrue) {
1049 hfpConfig.isEnabled = Boolean{ .value = true };
1050 return OK;
1051 } else if (trueOrFalse == AudioParameter::valueFalse) {
1052 hfpConfig.isEnabled = Boolean{ .value = false };
1053 return OK;
1054 }
1055 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1056 AudioParameter::keyBtHfpEnable, trueOrFalse.c_str());
1057 return BAD_VALUE;
1058 }));
1059 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1060 parameters, String8(AudioParameter::keyBtHfpSamplingRate),
1061 [&hfpConfig](int sampleRate) {
1062 return sampleRate > 0 ?
1063 hfpConfig.sampleRate = Int{ .value = sampleRate }, OK : BAD_VALUE;
1064 }));
1065 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1066 parameters, String8(AudioParameter::keyBtHfpVolume),
1067 [&hfpConfig](int volume0to15) {
1068 if (volume0to15 >= 0 && volume0to15 <= 15) {
1069 hfpConfig.volume = Float{ .value = volume0to15 / 15.0f };
1070 return OK;
1071 }
1072 return BAD_VALUE;
1073 }));
1074 if (mBluetooth != nullptr && hfpConfig != IBluetooth::HfpConfig{}) {
1075 IBluetooth::HfpConfig newHfpConfig;
1076 return statusTFromBinderStatus(mBluetooth->setHfpConfig(hfpConfig, &newHfpConfig));
1077 }
1078 return OK;
1079}
1080
1081status_t DeviceHalAidl::filterAndUpdateBtLeParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001082 std::optional<bool> leEnabled;
1083 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1084 parameters, String8(AudioParameter::keyBtLeSuspended),
1085 [&leEnabled](const String8& trueOrFalse) {
1086 if (trueOrFalse == AudioParameter::valueTrue) {
1087 leEnabled = false; // 'suspended' == true
1088 return OK;
1089 } else if (trueOrFalse == AudioParameter::valueFalse) {
1090 leEnabled = true; // 'suspended' == false
1091 return OK;
1092 }
1093 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1094 AudioParameter::keyBtLeSuspended, trueOrFalse.c_str());
1095 return BAD_VALUE;
1096 }));
1097 if (mBluetoothLe != nullptr && leEnabled.has_value()) {
1098 return statusTFromBinderStatus(mBluetoothLe->setEnabled(leEnabled.value()));
1099 }
1100 return OK;
1101}
1102
1103status_t DeviceHalAidl::filterAndUpdateBtScoParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001104 IBluetooth::ScoConfig scoConfig;
1105 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1106 parameters, String8(AudioParameter::keyBtSco),
1107 [&scoConfig](const String8& onOrOff) {
1108 if (onOrOff == AudioParameter::valueOn) {
1109 scoConfig.isEnabled = Boolean{ .value = true };
1110 return OK;
1111 } else if (onOrOff == AudioParameter::valueOff) {
1112 scoConfig.isEnabled = Boolean{ .value = false };
1113 return OK;
1114 }
1115 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1116 AudioParameter::keyBtSco, onOrOff.c_str());
1117 return BAD_VALUE;
1118 }));
1119 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1120 parameters, String8(AudioParameter::keyBtScoHeadsetName),
1121 [&scoConfig](const String8& name) {
1122 scoConfig.debugName = name;
1123 return OK;
1124 }));
1125 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1126 parameters, String8(AudioParameter::keyBtNrec),
1127 [&scoConfig](const String8& onOrOff) {
1128 if (onOrOff == AudioParameter::valueOn) {
1129 scoConfig.isNrecEnabled = Boolean{ .value = true };
1130 return OK;
1131 } else if (onOrOff == AudioParameter::valueOff) {
1132 scoConfig.isNrecEnabled = Boolean{ .value = false };
1133 return OK;
1134 }
1135 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1136 AudioParameter::keyBtNrec, onOrOff.c_str());
1137 return BAD_VALUE;
1138 }));
1139 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1140 parameters, String8(AudioParameter::keyBtScoWb),
1141 [&scoConfig](const String8& onOrOff) {
1142 if (onOrOff == AudioParameter::valueOn) {
1143 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO_WB;
1144 return OK;
1145 } else if (onOrOff == AudioParameter::valueOff) {
1146 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO;
1147 return OK;
1148 }
1149 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1150 AudioParameter::keyBtScoWb, onOrOff.c_str());
1151 return BAD_VALUE;
1152 }));
1153 if (mBluetooth != nullptr && scoConfig != IBluetooth::ScoConfig{}) {
1154 IBluetooth::ScoConfig newScoConfig;
1155 return statusTFromBinderStatus(mBluetooth->setScoConfig(scoConfig, &newScoConfig));
1156 }
1157 return OK;
1158}
1159
Mikhail Naganove92c34b2023-05-31 14:24:48 -07001160status_t DeviceHalAidl::filterAndUpdateScreenParameters(AudioParameter &parameters) {
Mikhail Naganove92c34b2023-05-31 14:24:48 -07001161 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1162 parameters, String8(AudioParameter::keyScreenState),
1163 [&](const String8& onOrOff) -> status_t {
1164 std::optional<bool> isTurnedOn;
1165 if (onOrOff == AudioParameter::valueOn) {
1166 isTurnedOn = true;
1167 } else if (onOrOff == AudioParameter::valueOff) {
1168 isTurnedOn = false;
1169 }
1170 if (!isTurnedOn.has_value()) {
1171 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1172 AudioParameter::keyScreenState, onOrOff.c_str());
1173 return BAD_VALUE;
1174 }
1175 return statusTFromBinderStatus(
1176 mModule->updateScreenState(isTurnedOn.value()));
1177 }));
1178 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1179 parameters, String8(AudioParameter::keyScreenRotation),
1180 [&](int rotationDegrees) -> status_t {
1181 IModule::ScreenRotation rotation;
1182 switch (rotationDegrees) {
1183 case 0: rotation = IModule::ScreenRotation::DEG_0; break;
1184 case 90: rotation = IModule::ScreenRotation::DEG_90; break;
1185 case 180: rotation = IModule::ScreenRotation::DEG_180; break;
1186 case 270: rotation = IModule::ScreenRotation::DEG_270; break;
1187 default:
1188 ALOGE("setParameters: parameter key \"%s\" has invalid value %d",
1189 AudioParameter::keyScreenRotation, rotationDegrees);
1190 return BAD_VALUE;
1191 }
1192 return statusTFromBinderStatus(mModule->updateScreenRotation(rotation));
1193 }));
1194 return OK;
1195}
1196
Mikhail Naganovb9a81312023-07-18 13:55:34 -07001197status_t DeviceHalAidl::filterAndUpdateTelephonyParameters(AudioParameter &parameters) {
Mikhail Naganovb9a81312023-07-18 13:55:34 -07001198 using TtyMode = ITelephony::TelecomConfig::TtyMode;
1199 ITelephony::TelecomConfig telConfig;
1200 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1201 parameters, String8(AudioParameter::keyTtyMode),
1202 [&telConfig](const String8& mode) {
1203 if (mode == AudioParameter::valueTtyModeOff) {
1204 telConfig.ttyMode = TtyMode::OFF;
1205 return OK;
1206 } else if (mode == AudioParameter::valueTtyModeFull) {
1207 telConfig.ttyMode = TtyMode::FULL;
1208 return OK;
1209 } else if (mode == AudioParameter::valueTtyModeHco) {
1210 telConfig.ttyMode = TtyMode::HCO;
1211 return OK;
1212 } else if (mode == AudioParameter::valueTtyModeVco) {
1213 telConfig.ttyMode = TtyMode::VCO;
1214 return OK;
1215 }
1216 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1217 AudioParameter::keyTtyMode, mode.c_str());
1218 return BAD_VALUE;
1219 }));
1220 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1221 parameters, String8(AudioParameter::keyHacSetting),
1222 [&telConfig](const String8& onOrOff) {
1223 if (onOrOff == AudioParameter::valueHacOn) {
1224 telConfig.isHacEnabled = Boolean{ .value = true };
1225 return OK;
1226 } else if (onOrOff == AudioParameter::valueHacOff) {
1227 telConfig.isHacEnabled = Boolean{ .value = false };
1228 return OK;
1229 }
1230 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1231 AudioParameter::keyHacSetting, onOrOff.c_str());
1232 return BAD_VALUE;
1233 }));
1234 if (mTelephony != nullptr && telConfig != ITelephony::TelecomConfig{}) {
1235 ITelephony::TelecomConfig newTelConfig;
1236 return statusTFromBinderStatus(
1237 mTelephony->setTelecomConfig(telConfig, &newTelConfig));
1238 }
1239 return OK;
1240}
1241
Mikhail Naganovdfd594e2023-02-08 16:59:41 -08001242void DeviceHalAidl::clearCallbacks(void* cookie) {
1243 std::lock_guard l(mLock);
1244 mCallbacks.erase(cookie);
1245}
1246
1247sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1248 return getCallbackImpl(cookie, &Callbacks::out);
1249}
1250
1251void DeviceHalAidl::setStreamOutCallback(
1252 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1253 setCallbackImpl(cookie, &Callbacks::out, cb);
1254}
1255
1256sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1257 void* cookie) {
1258 return getCallbackImpl(cookie, &Callbacks::event);
1259}
1260
1261void DeviceHalAidl::setStreamOutEventCallback(
1262 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1263 setCallbackImpl(cookie, &Callbacks::event, cb);
1264}
1265
1266sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1267 void* cookie) {
1268 return getCallbackImpl(cookie, &Callbacks::latency);
1269}
1270
1271void DeviceHalAidl::setStreamOutLatencyModeCallback(
1272 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1273 setCallbackImpl(cookie, &Callbacks::latency, cb);
1274}
1275
1276template<class C>
1277sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1278 std::lock_guard l(mLock);
1279 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1280 return ((it->second).*field).promote();
1281 }
1282 return nullptr;
1283}
1284template<class C>
1285void DeviceHalAidl::setCallbackImpl(
1286 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1287 std::lock_guard l(mLock);
1288 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1289 (it->second).*field = cb;
1290 }
1291}
1292
Mikhail Naganov31d46652023-01-10 18:29:25 +00001293} // namespace android