blob: 2af18cc1c2cfa522b4a00a947a62a12215f04415 [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)) {}
401 ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& in_audioMetadata) override {
402 std::basic_string<uint8_t> halMetadata(in_audioMetadata.begin(), in_audioMetadata.end());
403 return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb(
404 [&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); });
405 }
406 ndk::ScopedAStatus onRecommendedLatencyModeChanged(
407 const std::vector<AudioLatencyMode>& in_modes) override {
408 auto halModes = VALUE_OR_FATAL(
409 ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
410 in_modes,
411 ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
412 return StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::runCb(
413 [&halModes](auto cb) { cb->onRecommendedLatencyModeChanged(halModes); });
414 }
415};
416
417} // namespace
418
Mikhail Naganov31d46652023-01-10 18:29:25 +0000419status_t DeviceHalAidl::openOutputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800420 audio_io_handle_t handle, audio_devices_t devices,
421 audio_output_flags_t flags, struct audio_config* config,
422 const char* address,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000423 sp<StreamOutHalInterface>* outStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800424 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700425 TIME_CHECK();
426 if (mModule == nullptr) return NO_INIT;
427 if (outStream == nullptr || config == nullptr) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000428 return BAD_VALUE;
429 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700430 constexpr bool isInput = false;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800431 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
432 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
433 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700434 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, isInput));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800435 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
436 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
437 int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
438 ::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
439 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
440 AudioPortConfig mixPortConfig;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700441 AudioPatch aidlPatch;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700442 Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
443 {
444 std::lock_guard l(mLock);
445 RETURN_STATUS_IF_ERROR(mMapper.prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
446 AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
447 &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
448 }
449 *config = VALUE_OR_RETURN_STATUS(
450 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(aidlConfig, isInput));
Mikhail Naganovca92a5c2023-12-07 14:00:48 -0800451 if (mixPortConfig.id == 0) return BAD_VALUE; // HAL suggests a different config.
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800452 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
453 args.portConfigId = mixPortConfig.id;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800454 const bool isOffload = isBitPositionFlagSet(
455 aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD);
456 std::shared_ptr<OutputStreamCallbackAidl> streamCb;
457 if (isOffload) {
458 streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
459 }
460 auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
461 if (isOffload) {
462 args.offloadInfo = aidlConfig.offloadInfo;
463 args.callback = streamCb;
464 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800465 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800466 args.eventCallback = eventCb;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800467 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
468 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800469 StreamContextAidl context(ret.desc, isOffload);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800470 if (!context.isValid()) {
471 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
472 __func__, ret.desc.toString().c_str());
473 return NO_INIT;
474 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700475 *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700476 std::move(ret.stream), mVendorExt, this /*callbackBroker*/);
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800477 void* cbCookie = (*outStream).get();
478 {
479 std::lock_guard l(mLock);
480 mCallbacks.emplace(cbCookie, Callbacks{});
Mikhail Naganov78f7f9a2023-11-16 15:49:23 -0800481 mMapper.addStream(*outStream, mixPortConfig.id, aidlPatch.id);
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800482 }
483 if (streamCb) streamCb->setCookie(cbCookie);
484 eventCb->setCookie(cbCookie);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800485 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000486 return OK;
487}
488
Mikhail Naganov31d46652023-01-10 18:29:25 +0000489status_t DeviceHalAidl::openInputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800490 audio_io_handle_t handle, audio_devices_t devices,
491 struct audio_config* config, audio_input_flags_t flags,
492 const char* address, audio_source_t source,
493 audio_devices_t outputDevice, const char* outputDeviceAddress,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000494 sp<StreamInHalInterface>* inStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800495 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700496 TIME_CHECK();
497 if (mModule == nullptr) return NO_INIT;
498 if (inStream == nullptr || config == nullptr) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000499 return BAD_VALUE;
500 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700501 constexpr bool isInput = true;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800502 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
503 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
504 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700505 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, isInput));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800506 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
507 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
508 int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
509 ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
510 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
511 AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
512 ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
513 AudioPortConfig mixPortConfig;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700514 AudioPatch aidlPatch;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700515 Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
516 {
517 std::lock_guard l(mLock);
518 RETURN_STATUS_IF_ERROR(mMapper.prepareToOpenStream(
519 aidlHandle, aidlDevice, aidlFlags, aidlSource,
520 &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
521 }
522 *config = VALUE_OR_RETURN_STATUS(
523 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(aidlConfig, isInput));
Mikhail Naganovca92a5c2023-12-07 14:00:48 -0800524 if (mixPortConfig.id == 0) return BAD_VALUE; // HAL suggests a different config.
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800525 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
526 args.portConfigId = mixPortConfig.id;
527 RecordTrackMetadata aidlTrackMetadata{
528 .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
529 if (outputDevice != AUDIO_DEVICE_NONE) {
530 aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
531 ::aidl::android::legacy2aidl_audio_device_AudioDevice(
532 outputDevice, outputDeviceAddress));
533 }
534 args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
535 args.bufferSizeFrames = aidlConfig.frameCount;
536 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
537 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800538 StreamContextAidl context(ret.desc, false /*isAsynchronous*/);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800539 if (!context.isValid()) {
540 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
541 __func__, ret.desc.toString().c_str());
542 return NO_INIT;
543 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700544 *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700545 std::move(ret.stream), mVendorExt, this /*micInfoProvider*/);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700546 {
547 std::lock_guard l(mLock);
Mikhail Naganov78f7f9a2023-11-16 15:49:23 -0800548 mMapper.addStream(*inStream, mixPortConfig.id, aidlPatch.id);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700549 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800550 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000551 return OK;
552}
553
554status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700555 if (supportsPatches == nullptr) {
556 return BAD_VALUE;
557 }
Shunkai Yao51202502022-12-12 06:11:46 +0000558 *supportsPatches = true;
559 return OK;
560}
561
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800562status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
563 const struct audio_port_config* sources,
564 unsigned int num_sinks,
565 const struct audio_port_config* sinks,
566 audio_patch_handle_t* patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800567 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000568 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700569 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800570 if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
571 sources == nullptr || sinks == nullptr || patch == nullptr) {
572 return BAD_VALUE;
573 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800574 // When the patch handle (*patch) is AUDIO_PATCH_HANDLE_NONE, it means
575 // the framework wants to create a new patch. The handle has to be generated
576 // by the HAL. Since handles generated this way can only be unique within
577 // a HAL module, the framework generates a globally unique handle, and maps
578 // it on the <HAL module, patch handle> pair.
579 // When the patch handle is set, it meant the framework intends to update
580 // an existing patch.
581 //
582 // This behavior corresponds to HAL module behavior, with the only difference
583 // that the HAL module uses `int32_t` for patch IDs. The following assert ensures
584 // that both the framework and the HAL use the same value for "no ID":
585 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700586 int32_t aidlPatchId = static_cast<int32_t>(*patch);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800587
588 // Upon conversion, mix port configs contain audio configuration, while
589 // device port configs contain device address. This data is used to find
590 // or create HAL configs.
591 std::vector<AudioPortConfig> aidlSources, aidlSinks;
592 for (unsigned int i = 0; i < num_sources; ++i) {
593 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
594 sources[i].role, sources[i].type)) ==
595 ::aidl::android::AudioPortDirection::INPUT;
596 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
597 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
598 sources[i], isInput, 0)));
599 }
600 for (unsigned int i = 0; i < num_sinks; ++i) {
601 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
602 sinks[i].role, sinks[i].type)) ==
603 ::aidl::android::AudioPortDirection::INPUT;
604 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
605 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
606 sinks[i], isInput, 0)));
607 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700608 Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
609 {
610 std::lock_guard l(mLock);
611 RETURN_STATUS_IF_ERROR(mMapper.createOrUpdatePatch(
612 aidlSources, aidlSinks, &aidlPatchId, &cleanups));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800613 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700614 *patch = static_cast<audio_patch_handle_t>(aidlPatchId);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800615 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000616 return OK;
617}
618
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800619status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800620 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000621 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700622 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800623 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
624 if (patch == AUDIO_PATCH_HANDLE_NONE) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800625 return BAD_VALUE;
626 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700627 std::lock_guard l(mLock);
628 RETURN_STATUS_IF_ERROR(mMapper.releaseAudioPatch(static_cast<int32_t>(patch)));
Shunkai Yao51202502022-12-12 06:11:46 +0000629 return OK;
630}
631
Mikhail Naganove93a0862023-03-15 17:06:59 -0700632status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700633 if (port == nullptr) {
634 return BAD_VALUE;
635 }
636 audio_port_v7 portV7;
637 audio_populate_audio_port_v7(port, &portV7);
638 RETURN_STATUS_IF_ERROR(getAudioPort(&portV7));
639 return audio_populate_audio_port(&portV7, port) ? OK : BAD_VALUE;
640}
641
642status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
643 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
644 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700645 if (mModule == nullptr) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700646 if (port == nullptr) {
647 return BAD_VALUE;
648 }
649 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
650 ::aidl::android::AudioPortDirection::INPUT;
651 auto aidlPort = VALUE_OR_RETURN_STATUS(
652 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
653 if (aidlPort.ext.getTag() != AudioPortExt::device) {
654 ALOGE("%s: provided port is not a device port (module %s): %s",
655 __func__, mInstance.c_str(), aidlPort.toString().c_str());
656 return BAD_VALUE;
657 }
658 const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
659 // It seems that we don't have to call HAL since all valid ports have been added either
660 // during initialization, or while handling connection of an external device.
Mikhail Naganove93a0862023-03-15 17:06:59 -0700661 const int32_t fwkId = aidlPort.id;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700662 {
663 std::lock_guard l(mLock);
664 RETURN_STATUS_IF_ERROR(mMapper.getAudioPortCached(matchDevice, &aidlPort));
665 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700666 aidlPort.id = fwkId;
667 *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
668 aidlPort, isInput));
669 return OK;
670}
671
jiabin12537fc2023-10-12 17:56:08 +0000672status_t DeviceHalAidl::getAudioMixPort(const struct audio_port_v7 *devicePort,
673 struct audio_port_v7 *mixPort) {
674 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700675 TIME_CHECK();
676 if (mModule == nullptr) return NO_INIT;
677 if (devicePort == nullptr || mixPort == nullptr ||
678 devicePort->type != AUDIO_PORT_TYPE_DEVICE || mixPort->type != AUDIO_PORT_TYPE_MIX) {
jiabin12537fc2023-10-12 17:56:08 +0000679 return BAD_VALUE;
680 }
681 const int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
682 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(mixPort->ext.mix.handle));
jiabin12537fc2023-10-12 17:56:08 +0000683 AudioPort port;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700684 {
685 std::lock_guard l(mLock);
686 RETURN_STATUS_IF_ERROR(mMapper.getAudioMixPort(aidlHandle, &port));
jiabin12537fc2023-10-12 17:56:08 +0000687 }
688 const bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
689 mixPort->role, mixPort->type)) == ::aidl::android::AudioPortDirection::INPUT;
690 *mixPort = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
691 port, isInput));
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700692 return OK;
jiabin12537fc2023-10-12 17:56:08 +0000693}
694
Mikhail Naganove93a0862023-03-15 17:06:59 -0700695status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
696 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
697 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700698 if (mModule == nullptr) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700699 if (config == nullptr) {
700 return BAD_VALUE;
701 }
702 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
703 config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
704 AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
705 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
706 *config, isInput, 0 /*portId*/));
707 AudioPortConfig portConfig;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700708 std::lock_guard l(mLock);
Mikhail Naganovca92a5c2023-12-07 14:00:48 -0800709 return mMapper.setPortConfig(requestedPortConfig, std::set<int32_t>(), &portConfig);
Shunkai Yao51202502022-12-12 06:11:46 +0000710}
711
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800712MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700713 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
714 TIME_CHECK();
715 if (!mModule) return {};
716 std::lock_guard l(mLock);
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800717 if (mMicrophones.status == Microphones::Status::UNKNOWN) {
718 TIME_CHECK();
719 std::vector<MicrophoneInfo> aidlInfo;
720 status_t status = statusTFromBinderStatus(mModule->getMicrophones(&aidlInfo));
721 if (status == OK) {
722 mMicrophones.status = Microphones::Status::QUERIED;
723 mMicrophones.info = std::move(aidlInfo);
724 } else if (status == INVALID_OPERATION) {
725 mMicrophones.status = Microphones::Status::NOT_SUPPORTED;
726 } else {
727 ALOGE("%s: Unexpected status from 'IModule.getMicrophones': %d", __func__, status);
728 return {};
729 }
730 }
731 if (mMicrophones.status == Microphones::Status::QUERIED) {
732 return &mMicrophones.info;
733 }
734 return {}; // NOT_SUPPORTED
735}
736
Shunkai Yao51202502022-12-12 06:11:46 +0000737status_t DeviceHalAidl::getMicrophones(
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800738 std::vector<audio_microphone_characteristic_t>* microphones) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700739 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
740 TIME_CHECK();
741 if (mModule == nullptr) return NO_INIT;
742 if (microphones == nullptr) {
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800743 return BAD_VALUE;
744 }
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800745 auto staticInfo = getMicrophoneInfo();
746 if (!staticInfo) return INVALID_OPERATION;
747 std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
748 emptyDynamicInfo.reserve(staticInfo->size());
749 std::transform(staticInfo->begin(), staticInfo->end(), std::back_inserter(emptyDynamicInfo),
750 [](const auto& info) { return MicrophoneDynamicInfo{ .id = info.id }; });
751 *microphones = VALUE_OR_RETURN_STATUS(
752 ::aidl::android::convertContainers<std::vector<audio_microphone_characteristic_t>>(
753 *staticInfo, emptyDynamicInfo,
754 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t)
755 );
Shunkai Yao51202502022-12-12 06:11:46 +0000756 return OK;
757}
758
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700759status_t DeviceHalAidl::addDeviceEffect(
760 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700761 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700762 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700763 if (mModule == nullptr) return NO_INIT;
764 if (device == nullptr || effect == nullptr) {
Shunkai Yao51202502022-12-12 06:11:46 +0000765 return BAD_VALUE;
766 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700767 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
768 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
769 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
770 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
771 *device, isInput, 0));
772 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
773 ALOGE("%s: provided port config is not a device port config: %s",
774 __func__, requestedPortConfig.toString().c_str());
775 return BAD_VALUE;
776 }
777 AudioPortConfig devicePortConfig;
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700778 Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
779 {
780 std::lock_guard l(mLock);
Mikhail Naganovca92a5c2023-12-07 14:00:48 -0800781 RETURN_STATUS_IF_ERROR(mMapper.setPortConfig(
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700782 requestedPortConfig, {} /*destinationPortIds*/, &devicePortConfig, &cleanups));
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700783 }
784 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
785 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->addDeviceEffect(
786 devicePortConfig.id, aidlEffect->getIEffect())));
787 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000788 return OK;
789}
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700790status_t DeviceHalAidl::removeDeviceEffect(
791 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700792 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700793 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700794 if (mModule == nullptr) return NO_INIT;
795 if (device == nullptr || effect == nullptr) {
Shunkai Yao51202502022-12-12 06:11:46 +0000796 return BAD_VALUE;
797 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700798 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
799 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
800 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
801 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
802 *device, isInput, 0));
803 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
804 ALOGE("%s: provided port config is not a device port config: %s",
805 __func__, requestedPortConfig.toString().c_str());
806 return BAD_VALUE;
807 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700808 AudioPortConfig devicePortConfig;
809 {
810 std::lock_guard l(mLock);
811 RETURN_STATUS_IF_ERROR(mMapper.findPortConfig(
812 requestedPortConfig.ext.get<AudioPortExt::Tag::device>().device,
813 &devicePortConfig));
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700814 }
815 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
816 return statusTFromBinderStatus(mModule->removeDeviceEffect(
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700817 devicePortConfig.id, aidlEffect->getIEffect()));
Shunkai Yao51202502022-12-12 06:11:46 +0000818}
819
820status_t DeviceHalAidl::getMmapPolicyInfos(
David Li9cf5e622023-03-21 00:51:10 +0800821 media::audio::common::AudioMMapPolicyType policyType,
822 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700823 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000824 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700825 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov25bc9a22023-04-21 18:48:16 -0700826 AudioMMapPolicyType mmapPolicyType = VALUE_OR_RETURN_STATUS(
827 cpp2ndk_AudioMMapPolicyType(policyType));
David Li9cf5e622023-03-21 00:51:10 +0800828
829 std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
830
831 if (status_t status = statusTFromBinderStatus(
832 mModule->getMmapPolicyInfos(mmapPolicyType, &mmapPolicyInfos)); status != OK) {
833 return status;
834 }
835
836 *policyInfos = VALUE_OR_RETURN_STATUS(
837 convertContainer<std::vector<media::audio::common::AudioMMapPolicyInfo>>(
838 mmapPolicyInfos, ndk2cpp_AudioMMapPolicyInfo));
Shunkai Yao51202502022-12-12 06:11:46 +0000839 return OK;
840}
841
842int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700843 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000844 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700845 if (mModule == nullptr) return NO_INIT;
David Li9cf5e622023-03-21 00:51:10 +0800846 int32_t mixerBurstCount = 0;
847 if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
848 return mixerBurstCount;
849 }
850 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000851}
852
853int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700854 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000855 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700856 if (mModule == nullptr) return NO_INIT;
David Li9cf5e622023-03-21 00:51:10 +0800857 int32_t hardwareBurstMinUsec = 0;
858 if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
859 return hardwareBurstMinUsec;
860 }
861 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000862}
863
864error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700865 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000866 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700867 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700868 int32_t aidlHwAvSync;
869 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
870 return VALUE_OR_RETURN_STATUS(
871 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +0000872}
873
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000874status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
875 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700876 if (mModule == nullptr) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000877 return mModule->dump(fd, Args(args).args(), args.size());
David Li9cf5e622023-03-21 00:51:10 +0800878}
Shunkai Yao51202502022-12-12 06:11:46 +0000879
Eric Laurent7af6ee72023-06-29 11:44:54 +0200880status_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700881 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000882 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700883 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700884 if (supports == nullptr) {
885 return BAD_VALUE;
886 }
887 return statusTFromBinderStatus(mModule->supportsVariableLatency(supports));
Shunkai Yao51202502022-12-12 06:11:46 +0000888}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000889
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100890status_t DeviceHalAidl::getSoundDoseInterface(const std::string& module,
891 ::ndk::SpAIBinder* soundDoseBinder) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700892 if (soundDoseBinder == nullptr) {
893 return BAD_VALUE;
894 }
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100895 if (mSoundDose == nullptr) {
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700896 ALOGE("%s failed to retrieve the sound dose interface for module %s",
897 __func__, module.c_str());
898 return BAD_VALUE;
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100899 }
900 *soundDoseBinder = mSoundDose->asBinder();
901 ALOGI("%s using audio AIDL HAL sound dose interface", __func__);
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100902 return OK;
903}
jiabin872de702023-04-27 22:04:31 +0000904
905status_t DeviceHalAidl::prepareToDisconnectExternalDevice(const struct audio_port_v7* port) {
jiabin62750c22023-12-21 22:06:07 +0000906 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
907 TIME_CHECK();
908 if (mModule == nullptr) return NO_INIT;
909 if (port == nullptr) {
910 return BAD_VALUE;
911 }
912 const bool isInput = VALUE_OR_RETURN_STATUS(
913 ::aidl::android::portDirection(port->role, port->type)) ==
914 ::aidl::android::AudioPortDirection::INPUT;
915 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
916 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
917 if (aidlPort.ext.getTag() != AudioPortExt::device) {
918 ALOGE("%s: provided port is not a device port (module %s): %s",
919 __func__, mInstance.c_str(), aidlPort.toString().c_str());
920 return BAD_VALUE;
921 }
922 status_t status = NO_ERROR;
923 {
924 std::lock_guard l(mLock);
925 status = mMapper.prepareToDisconnectExternalDevice(aidlPort);
926 }
927 if (status == UNKNOWN_TRANSACTION) {
928 // If there is not AIDL API defined for `prepareToDisconnectExternalDevice`.
929 // Call `setConnectedState` instead.
930 RETURN_STATUS_IF_ERROR(setConnectedState(port, false /*connected*/));
931 std::lock_guard l(mLock);
932 mDeviceDisconnectionNotified.insert(port->id);
933 // Return that there was no error as otherwise the disconnection procedure will not be
934 // considered complete for upper layers, and 'setConnectedState' will not be called again
935 return OK;
936 } else {
937 return status;
938 }
jiabin872de702023-04-27 22:04:31 +0000939}
940
Mikhail Naganove93a0862023-03-15 17:06:59 -0700941status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
Mikhail Naganovae9063d2023-11-07 16:43:51 -0800942 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700943 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700944 if (mModule == nullptr) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700945 if (port == nullptr) {
946 return BAD_VALUE;
947 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700948 if (!connected) {
949 std::lock_guard l(mLock);
950 if (mDeviceDisconnectionNotified.erase(port->id) > 0) {
951 // For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
jiabin62750c22023-12-21 22:06:07 +0000952 // and then call `setConnectedState`. If `prepareToDisconnectExternalDevice` doesn't
953 // exit, `setConnectedState` will be called when calling
954 // `prepareToDisconnectExternalDevice`. Do not call to the HAL if previous call is
955 // successful. Also remove the cache here to avoid a large cache after a long run.
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700956 return OK;
957 }
jiabin872de702023-04-27 22:04:31 +0000958 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700959 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
960 ::aidl::android::AudioPortDirection::INPUT;
961 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
962 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
963 if (aidlPort.ext.getTag() != AudioPortExt::device) {
964 ALOGE("%s: provided port is not a device port (module %s): %s",
965 __func__, mInstance.c_str(), aidlPort.toString().c_str());
966 return BAD_VALUE;
967 }
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700968 std::lock_guard l(mLock);
969 return mMapper.setDevicePortConnectedState(aidlPort, connected);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700970}
971
972status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
973 TIME_CHECK();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700974 if (mModule == nullptr) return NO_INIT;
975 {
976 std::lock_guard l(mLock);
Mikhail Naganov15520da2024-01-17 11:15:20 -0800977 mMapper.resetUnusedPatchesPortConfigsAndPorts();
Mikhail Naganovac9d4e72023-10-23 12:00:09 -0700978 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700979 ModuleDebug debug{ .simulateDeviceConnections = enabled };
980 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
981 // This is important to log as it affects HAL behavior.
982 if (status == OK) {
983 ALOGI("%s: set enabled: %d", __func__, enabled);
984 } else {
985 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
986 }
987 return status;
988}
989
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700990status_t DeviceHalAidl::filterAndRetrieveBtA2dpParameters(
991 AudioParameter &keys, AudioParameter *result) {
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700992 if (String8 key = String8(AudioParameter::keyReconfigA2dpSupported); keys.containsKey(key)) {
993 keys.remove(key);
David Lia7761ed2023-11-03 17:22:07 +0000994 if (mBluetoothA2dp != nullptr) {
995 bool supports;
996 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
997 mBluetoothA2dp->supportsOffloadReconfiguration(&supports)));
998 result->addInt(key, supports ? 1 : 0);
999 } else {
1000 ALOGI("%s: no IBluetoothA2dp on %s", __func__, mInstance.c_str());
1001 result->addInt(key, 0);
1002 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001003 }
1004 return OK;
1005}
1006
Mikhail Naganovccc82112023-04-27 18:14:15 -07001007status_t DeviceHalAidl::filterAndUpdateBtA2dpParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001008 std::optional<bool> a2dpEnabled;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001009 std::optional<std::vector<VendorParameter>> reconfigureOffload;
Mikhail Naganovccc82112023-04-27 18:14:15 -07001010 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1011 parameters, String8(AudioParameter::keyBtA2dpSuspended),
1012 [&a2dpEnabled](const String8& trueOrFalse) {
1013 if (trueOrFalse == AudioParameter::valueTrue) {
1014 a2dpEnabled = false; // 'suspended' == true
1015 return OK;
1016 } else if (trueOrFalse == AudioParameter::valueFalse) {
1017 a2dpEnabled = true; // 'suspended' == false
1018 return OK;
1019 }
1020 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1021 AudioParameter::keyBtA2dpSuspended, trueOrFalse.c_str());
1022 return BAD_VALUE;
1023 }));
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001024 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1025 parameters, String8(AudioParameter::keyReconfigA2dp),
1026 [&](const String8& value) -> status_t {
Dan Shi1eaa2242024-02-01 19:32:34 +00001027 if (mVendorExt != nullptr) {
1028 std::vector<VendorParameter> result;
1029 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1030 mVendorExt->parseBluetoothA2dpReconfigureOffload(
1031 std::string(value.c_str()), &result)));
1032 reconfigureOffload = std::move(result);
1033 } else {
1034 reconfigureOffload = std::vector<VendorParameter>();
1035 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001036 return OK;
1037 }));
Mikhail Naganovccc82112023-04-27 18:14:15 -07001038 if (mBluetoothA2dp != nullptr && a2dpEnabled.has_value()) {
1039 return statusTFromBinderStatus(mBluetoothA2dp->setEnabled(a2dpEnabled.value()));
1040 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001041 if (mBluetoothA2dp != nullptr && reconfigureOffload.has_value()) {
1042 return statusTFromBinderStatus(mBluetoothA2dp->reconfigureOffload(
1043 reconfigureOffload.value()));
1044 }
Mikhail Naganovccc82112023-04-27 18:14:15 -07001045 return OK;
1046}
1047
1048status_t DeviceHalAidl::filterAndUpdateBtHfpParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001049 IBluetooth::HfpConfig hfpConfig;
1050 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1051 parameters, String8(AudioParameter::keyBtHfpEnable),
1052 [&hfpConfig](const String8& trueOrFalse) {
1053 if (trueOrFalse == AudioParameter::valueTrue) {
1054 hfpConfig.isEnabled = Boolean{ .value = true };
1055 return OK;
1056 } else if (trueOrFalse == AudioParameter::valueFalse) {
1057 hfpConfig.isEnabled = Boolean{ .value = false };
1058 return OK;
1059 }
1060 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1061 AudioParameter::keyBtHfpEnable, trueOrFalse.c_str());
1062 return BAD_VALUE;
1063 }));
1064 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1065 parameters, String8(AudioParameter::keyBtHfpSamplingRate),
1066 [&hfpConfig](int sampleRate) {
1067 return sampleRate > 0 ?
1068 hfpConfig.sampleRate = Int{ .value = sampleRate }, OK : BAD_VALUE;
1069 }));
1070 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1071 parameters, String8(AudioParameter::keyBtHfpVolume),
1072 [&hfpConfig](int volume0to15) {
1073 if (volume0to15 >= 0 && volume0to15 <= 15) {
1074 hfpConfig.volume = Float{ .value = volume0to15 / 15.0f };
1075 return OK;
1076 }
1077 return BAD_VALUE;
1078 }));
1079 if (mBluetooth != nullptr && hfpConfig != IBluetooth::HfpConfig{}) {
1080 IBluetooth::HfpConfig newHfpConfig;
1081 return statusTFromBinderStatus(mBluetooth->setHfpConfig(hfpConfig, &newHfpConfig));
1082 }
1083 return OK;
1084}
1085
1086status_t DeviceHalAidl::filterAndUpdateBtLeParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001087 std::optional<bool> leEnabled;
1088 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1089 parameters, String8(AudioParameter::keyBtLeSuspended),
1090 [&leEnabled](const String8& trueOrFalse) {
1091 if (trueOrFalse == AudioParameter::valueTrue) {
1092 leEnabled = false; // 'suspended' == true
1093 return OK;
1094 } else if (trueOrFalse == AudioParameter::valueFalse) {
1095 leEnabled = true; // 'suspended' == false
1096 return OK;
1097 }
1098 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1099 AudioParameter::keyBtLeSuspended, trueOrFalse.c_str());
1100 return BAD_VALUE;
1101 }));
1102 if (mBluetoothLe != nullptr && leEnabled.has_value()) {
1103 return statusTFromBinderStatus(mBluetoothLe->setEnabled(leEnabled.value()));
1104 }
1105 return OK;
1106}
1107
1108status_t DeviceHalAidl::filterAndUpdateBtScoParameters(AudioParameter &parameters) {
Mikhail Naganovccc82112023-04-27 18:14:15 -07001109 IBluetooth::ScoConfig scoConfig;
1110 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1111 parameters, String8(AudioParameter::keyBtSco),
1112 [&scoConfig](const String8& onOrOff) {
1113 if (onOrOff == AudioParameter::valueOn) {
1114 scoConfig.isEnabled = Boolean{ .value = true };
1115 return OK;
1116 } else if (onOrOff == AudioParameter::valueOff) {
1117 scoConfig.isEnabled = Boolean{ .value = false };
1118 return OK;
1119 }
1120 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1121 AudioParameter::keyBtSco, onOrOff.c_str());
1122 return BAD_VALUE;
1123 }));
1124 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1125 parameters, String8(AudioParameter::keyBtScoHeadsetName),
1126 [&scoConfig](const String8& name) {
1127 scoConfig.debugName = name;
1128 return OK;
1129 }));
1130 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1131 parameters, String8(AudioParameter::keyBtNrec),
1132 [&scoConfig](const String8& onOrOff) {
1133 if (onOrOff == AudioParameter::valueOn) {
1134 scoConfig.isNrecEnabled = Boolean{ .value = true };
1135 return OK;
1136 } else if (onOrOff == AudioParameter::valueOff) {
1137 scoConfig.isNrecEnabled = Boolean{ .value = false };
1138 return OK;
1139 }
1140 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1141 AudioParameter::keyBtNrec, onOrOff.c_str());
1142 return BAD_VALUE;
1143 }));
1144 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1145 parameters, String8(AudioParameter::keyBtScoWb),
1146 [&scoConfig](const String8& onOrOff) {
1147 if (onOrOff == AudioParameter::valueOn) {
1148 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO_WB;
1149 return OK;
1150 } else if (onOrOff == AudioParameter::valueOff) {
1151 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO;
1152 return OK;
1153 }
1154 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1155 AudioParameter::keyBtScoWb, onOrOff.c_str());
1156 return BAD_VALUE;
1157 }));
1158 if (mBluetooth != nullptr && scoConfig != IBluetooth::ScoConfig{}) {
1159 IBluetooth::ScoConfig newScoConfig;
1160 return statusTFromBinderStatus(mBluetooth->setScoConfig(scoConfig, &newScoConfig));
1161 }
1162 return OK;
1163}
1164
Mikhail Naganove92c34b2023-05-31 14:24:48 -07001165status_t DeviceHalAidl::filterAndUpdateScreenParameters(AudioParameter &parameters) {
Mikhail Naganove92c34b2023-05-31 14:24:48 -07001166 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1167 parameters, String8(AudioParameter::keyScreenState),
1168 [&](const String8& onOrOff) -> status_t {
1169 std::optional<bool> isTurnedOn;
1170 if (onOrOff == AudioParameter::valueOn) {
1171 isTurnedOn = true;
1172 } else if (onOrOff == AudioParameter::valueOff) {
1173 isTurnedOn = false;
1174 }
1175 if (!isTurnedOn.has_value()) {
1176 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1177 AudioParameter::keyScreenState, onOrOff.c_str());
1178 return BAD_VALUE;
1179 }
1180 return statusTFromBinderStatus(
1181 mModule->updateScreenState(isTurnedOn.value()));
1182 }));
1183 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1184 parameters, String8(AudioParameter::keyScreenRotation),
1185 [&](int rotationDegrees) -> status_t {
1186 IModule::ScreenRotation rotation;
1187 switch (rotationDegrees) {
1188 case 0: rotation = IModule::ScreenRotation::DEG_0; break;
1189 case 90: rotation = IModule::ScreenRotation::DEG_90; break;
1190 case 180: rotation = IModule::ScreenRotation::DEG_180; break;
1191 case 270: rotation = IModule::ScreenRotation::DEG_270; break;
1192 default:
1193 ALOGE("setParameters: parameter key \"%s\" has invalid value %d",
1194 AudioParameter::keyScreenRotation, rotationDegrees);
1195 return BAD_VALUE;
1196 }
1197 return statusTFromBinderStatus(mModule->updateScreenRotation(rotation));
1198 }));
1199 return OK;
1200}
1201
Mikhail Naganovb9a81312023-07-18 13:55:34 -07001202status_t DeviceHalAidl::filterAndUpdateTelephonyParameters(AudioParameter &parameters) {
Mikhail Naganovb9a81312023-07-18 13:55:34 -07001203 using TtyMode = ITelephony::TelecomConfig::TtyMode;
1204 ITelephony::TelecomConfig telConfig;
1205 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1206 parameters, String8(AudioParameter::keyTtyMode),
1207 [&telConfig](const String8& mode) {
1208 if (mode == AudioParameter::valueTtyModeOff) {
1209 telConfig.ttyMode = TtyMode::OFF;
1210 return OK;
1211 } else if (mode == AudioParameter::valueTtyModeFull) {
1212 telConfig.ttyMode = TtyMode::FULL;
1213 return OK;
1214 } else if (mode == AudioParameter::valueTtyModeHco) {
1215 telConfig.ttyMode = TtyMode::HCO;
1216 return OK;
1217 } else if (mode == AudioParameter::valueTtyModeVco) {
1218 telConfig.ttyMode = TtyMode::VCO;
1219 return OK;
1220 }
1221 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1222 AudioParameter::keyTtyMode, mode.c_str());
1223 return BAD_VALUE;
1224 }));
1225 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1226 parameters, String8(AudioParameter::keyHacSetting),
1227 [&telConfig](const String8& onOrOff) {
1228 if (onOrOff == AudioParameter::valueHacOn) {
1229 telConfig.isHacEnabled = Boolean{ .value = true };
1230 return OK;
1231 } else if (onOrOff == AudioParameter::valueHacOff) {
1232 telConfig.isHacEnabled = Boolean{ .value = false };
1233 return OK;
1234 }
1235 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1236 AudioParameter::keyHacSetting, onOrOff.c_str());
1237 return BAD_VALUE;
1238 }));
1239 if (mTelephony != nullptr && telConfig != ITelephony::TelecomConfig{}) {
1240 ITelephony::TelecomConfig newTelConfig;
1241 return statusTFromBinderStatus(
1242 mTelephony->setTelecomConfig(telConfig, &newTelConfig));
1243 }
1244 return OK;
1245}
1246
Mikhail Naganovdfd594e2023-02-08 16:59:41 -08001247void DeviceHalAidl::clearCallbacks(void* cookie) {
1248 std::lock_guard l(mLock);
1249 mCallbacks.erase(cookie);
1250}
1251
1252sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1253 return getCallbackImpl(cookie, &Callbacks::out);
1254}
1255
1256void DeviceHalAidl::setStreamOutCallback(
1257 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1258 setCallbackImpl(cookie, &Callbacks::out, cb);
1259}
1260
1261sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1262 void* cookie) {
1263 return getCallbackImpl(cookie, &Callbacks::event);
1264}
1265
1266void DeviceHalAidl::setStreamOutEventCallback(
1267 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1268 setCallbackImpl(cookie, &Callbacks::event, cb);
1269}
1270
1271sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1272 void* cookie) {
1273 return getCallbackImpl(cookie, &Callbacks::latency);
1274}
1275
1276void DeviceHalAidl::setStreamOutLatencyModeCallback(
1277 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1278 setCallbackImpl(cookie, &Callbacks::latency, cb);
1279}
1280
1281template<class C>
1282sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1283 std::lock_guard l(mLock);
1284 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1285 return ((it->second).*field).promote();
1286 }
1287 return nullptr;
1288}
1289template<class C>
1290void DeviceHalAidl::setCallbackImpl(
1291 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1292 std::lock_guard l(mLock);
1293 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1294 (it->second).*field = cb;
1295 }
1296}
1297
Mikhail Naganov31d46652023-01-10 18:29:25 +00001298} // namespace android