blob: 5bc25ae9043dd50d5d261bfcbbc727909009aee4 [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>
21#include <forward_list>
22
Mikhail Naganovdfd594e2023-02-08 16:59:41 -080023#include <aidl/android/hardware/audio/core/BnStreamCallback.h>
24#include <aidl/android/hardware/audio/core/BnStreamOutEventCallback.h>
Mikhail Naganovfab697c2023-01-11 19:33:13 +000025#include <aidl/android/hardware/audio/core/StreamDescriptor.h>
26#include <error/expected_utils.h>
27#include <media/AidlConversionCppNdk.h>
Mikhail Naganov25bc9a22023-04-21 18:48:16 -070028#include <media/AidlConversionNdkCpp.h>
Mikhail Naganovfab697c2023-01-11 19:33:13 +000029#include <media/AidlConversionUtil.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000030#include <mediautils/TimeCheck.h>
Mikhail Naganovae9063d2023-11-07 16:43:51 -080031#include <system/audio.h>
Mikhail Naganov89a9f742023-01-30 12:33:18 -080032#include <Utils.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000033#include <utils/Log.h>
Shunkai Yao51202502022-12-12 06:11:46 +000034
Mikhail Naganov31d46652023-01-10 18:29:25 +000035#include "DeviceHalAidl.h"
Mikhail Naganova82a69d2023-06-14 16:31:32 -070036#include "EffectHalAidl.h"
Mikhail Naganov31d46652023-01-10 18:29:25 +000037#include "StreamHalAidl.h"
38
Mikhail Naganovfab697c2023-01-11 19:33:13 +000039using aidl::android::aidl_utils::statusTFromBinderStatus;
Mikhail Naganovccc82112023-04-27 18:14:15 -070040using aidl::android::media::audio::common::Boolean;
Mikhail Naganove93a0862023-03-15 17:06:59 -070041using aidl::android::media::audio::common::AudioChannelLayout;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080042using aidl::android::media::audio::common::AudioConfig;
43using aidl::android::media::audio::common::AudioDevice;
David Li9cf5e622023-03-21 00:51:10 +080044using aidl::android::media::audio::common::AudioDeviceAddress;
Mikhail Naganovae9063d2023-11-07 16:43:51 -080045using aidl::android::media::audio::common::AudioDeviceDescription;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080046using aidl::android::media::audio::common::AudioDeviceType;
Mikhail Naganov69557132023-09-07 15:29:01 -070047using aidl::android::media::audio::common::AudioFormatDescription;
Mikhail Naganove93a0862023-03-15 17:06:59 -070048using aidl::android::media::audio::common::AudioFormatType;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080049using aidl::android::media::audio::common::AudioInputFlags;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080050using aidl::android::media::audio::common::AudioIoFlags;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -080051using aidl::android::media::audio::common::AudioLatencyMode;
David Li9cf5e622023-03-21 00:51:10 +080052using aidl::android::media::audio::common::AudioMMapPolicy;
53using aidl::android::media::audio::common::AudioMMapPolicyInfo;
54using aidl::android::media::audio::common::AudioMMapPolicyType;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000055using aidl::android::media::audio::common::AudioMode;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080056using aidl::android::media::audio::common::AudioOutputFlags;
57using aidl::android::media::audio::common::AudioPort;
58using aidl::android::media::audio::common::AudioPortConfig;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080059using aidl::android::media::audio::common::AudioPortDeviceExt;
David Li9cf5e622023-03-21 00:51:10 +080060using aidl::android::media::audio::common::AudioPortExt;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -080061using aidl::android::media::audio::common::AudioPortMixExt;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -080062using aidl::android::media::audio::common::AudioPortMixExtUseCase;
Mikhail Naganove93a0862023-03-15 17:06:59 -070063using aidl::android::media::audio::common::AudioProfile;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080064using aidl::android::media::audio::common::AudioSource;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000065using aidl::android::media::audio::common::Float;
David Li9cf5e622023-03-21 00:51:10 +080066using aidl::android::media::audio::common::Int;
67using aidl::android::media::audio::common::MicrophoneDynamicInfo;
68using aidl::android::media::audio::common::MicrophoneInfo;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -070069using aidl::android::media::audio::IHalAdapterVendorExtension;
Mikhail Naganov6352e822023-03-09 18:22:36 -080070using aidl::android::hardware::audio::common::getFrameSizeInBytes;
71using aidl::android::hardware::audio::common::isBitPositionFlagSet;
Mikhail Naganove93a0862023-03-15 17:06:59 -070072using aidl::android::hardware::audio::common::isDefaultAudioFormat;
Mikhail Naganov6352e822023-03-09 18:22:36 -080073using aidl::android::hardware::audio::common::makeBitPositionFlagMask;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080074using aidl::android::hardware::audio::common::RecordTrackMetadata;
75using aidl::android::hardware::audio::core::AudioPatch;
Mikhail Naganov289468a2023-03-29 10:06:15 -070076using aidl::android::hardware::audio::core::AudioRoute;
Mikhail Naganovccc82112023-04-27 18:14:15 -070077using aidl::android::hardware::audio::core::IBluetooth;
78using aidl::android::hardware::audio::core::IBluetoothA2dp;
79using aidl::android::hardware::audio::core::IBluetoothLe;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000080using aidl::android::hardware::audio::core::IModule;
81using aidl::android::hardware::audio::core::ITelephony;
Mikhail Naganove93a0862023-03-15 17:06:59 -070082using aidl::android::hardware::audio::core::ModuleDebug;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000083using aidl::android::hardware::audio::core::StreamDescriptor;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -070084using aidl::android::hardware::audio::core::VendorParameter;
Mikhail Naganov31d46652023-01-10 18:29:25 +000085
86namespace android {
87
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080088namespace {
89
90bool isConfigEqualToPortConfig(const AudioConfig& config, const AudioPortConfig& portConfig) {
91 return portConfig.sampleRate.value().value == config.base.sampleRate &&
92 portConfig.channelMask.value() == config.base.channelMask &&
93 portConfig.format.value() == config.base.format;
94}
95
96void setConfigFromPortConfig(AudioConfig* config, const AudioPortConfig& portConfig) {
97 config->base.sampleRate = portConfig.sampleRate.value().value;
98 config->base.channelMask = portConfig.channelMask.value();
99 config->base.format = portConfig.format.value();
100}
101
102void setPortConfigFromConfig(AudioPortConfig* portConfig, const AudioConfig& config) {
Mikhail Naganov69557132023-09-07 15:29:01 -0700103 if (config.base.sampleRate != 0) {
104 portConfig->sampleRate = Int{ .value = config.base.sampleRate };
105 }
106 if (config.base.channelMask != AudioChannelLayout{}) {
107 portConfig->channelMask = config.base.channelMask;
108 }
109 if (config.base.format != AudioFormatDescription{}) {
110 portConfig->format = config.base.format;
111 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800112}
113
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700114// Note: these converters are for types defined in different AIDL files. Although these
115// AIDL files are copies of each other, however formally these are different types
116// thus we don't use a conversion via a parcelable.
117ConversionResult<media::AudioRoute> ndk2cpp_AudioRoute(const AudioRoute& ndk) {
118 media::AudioRoute cpp;
119 cpp.sourcePortIds.insert(
120 cpp.sourcePortIds.end(), ndk.sourcePortIds.begin(), ndk.sourcePortIds.end());
121 cpp.sinkPortId = ndk.sinkPortId;
122 cpp.isExclusive = ndk.isExclusive;
David Li9cf5e622023-03-21 00:51:10 +0800123 return cpp;
124}
125
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700126template<typename T>
127std::shared_ptr<T> retrieveSubInterface(const std::shared_ptr<IModule>& module,
128 ::ndk::ScopedAStatus (IModule::*getT)(std::shared_ptr<T>*)) {
129 if (module != nullptr) {
130 std::shared_ptr<T> instance;
131 if (auto status = (module.get()->*getT)(&instance); status.isOk()) {
132 return instance;
133 }
134 }
135 return nullptr;
136}
137
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800138} // namespace
139
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700140DeviceHalAidl::DeviceHalAidl(const std::string& instance, const std::shared_ptr<IModule>& module,
141 const std::shared_ptr<IHalAdapterVendorExtension>& vext)
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700142 : ConversionHelperAidl("DeviceHalAidl"),
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700143 mInstance(instance), mModule(module), mVendorExt(vext),
Mikhail Naganovccc82112023-04-27 18:14:15 -0700144 mTelephony(retrieveSubInterface<ITelephony>(module, &IModule::getTelephony)),
145 mBluetooth(retrieveSubInterface<IBluetooth>(module, &IModule::getBluetooth)),
146 mBluetoothA2dp(retrieveSubInterface<IBluetoothA2dp>(module, &IModule::getBluetoothA2dp)),
147 mBluetoothLe(retrieveSubInterface<IBluetoothLe>(module, &IModule::getBluetoothLe)) {
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700148}
149
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700150status_t DeviceHalAidl::getAudioPorts(std::vector<media::audio::common::AudioPort> *ports) {
Mikhail Naganov9e459d72023-05-05 17:36:39 -0700151 return ::aidl::android::convertContainer(mPorts, ports,
152 [](const Ports::value_type& pair) { return ndk2cpp_AudioPort(pair.second); });
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700153}
154
155status_t DeviceHalAidl::getAudioRoutes(std::vector<media::AudioRoute> *routes) {
156 *routes = VALUE_OR_RETURN_STATUS(
157 ::aidl::android::convertContainer<std::vector<media::AudioRoute>>(
158 mRoutes, ndk2cpp_AudioRoute));
159 return OK;
160}
161
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700162status_t DeviceHalAidl::getSupportedModes(std::vector<media::audio::common::AudioMode> *modes) {
163 TIME_CHECK();
164 if (modes == nullptr) {
165 return BAD_VALUE;
166 }
167 if (mModule == nullptr) return NO_INIT;
168 if (mTelephony == nullptr) return INVALID_OPERATION;
169 std::vector<AudioMode> aidlModes;
170 RETURN_STATUS_IF_ERROR(
171 statusTFromBinderStatus(mTelephony->getSupportedAudioModes(&aidlModes)));
172 *modes = VALUE_OR_RETURN_STATUS(
173 ::aidl::android::convertContainer<std::vector<media::audio::common::AudioMode>>(
174 aidlModes, ndk2cpp_AudioMode));
175 return OK;
176}
177
Mikhail Naganov31d46652023-01-10 18:29:25 +0000178status_t DeviceHalAidl::getSupportedDevices(uint32_t*) {
179 // Obsolete.
180 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +0000181}
182
183status_t DeviceHalAidl::initCheck() {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800184 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000185 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800186 std::vector<AudioPort> ports;
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700187 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800188 ALOGW_IF(ports.empty(), "%s: module %s returned an empty list of audio ports",
189 __func__, mInstance.c_str());
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800190 mDefaultInputPortId = mDefaultOutputPortId = -1;
191 const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
Mikhail Naganovae9063d2023-11-07 16:43:51 -0800192 for (auto it = ports.begin(); it != ports.end(); ) {
193 const auto& port = *it;
194 if (port.ext.getTag() != AudioPortExt::Tag::device) {
195 ++it;
196 continue;
197 }
198 const AudioPortDeviceExt& deviceExt = port.ext.get<AudioPortExt::Tag::device>();
199 if ((deviceExt.flags & defaultDeviceFlag) != 0) {
200 if (port.flags.getTag() == AudioIoFlags::Tag::input) {
201 mDefaultInputPortId = port.id;
202 } else if (port.flags.getTag() == AudioIoFlags::Tag::output) {
203 mDefaultOutputPortId = port.id;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800204 }
205 }
Mikhail Naganovae9063d2023-11-07 16:43:51 -0800206 // For compatibility with HIDL, hide "template" remote submix ports from ports list.
207 if (const auto& devDesc = deviceExt.device;
208 (devDesc.type.type == AudioDeviceType::IN_SUBMIX ||
209 devDesc.type.type == AudioDeviceType::OUT_SUBMIX) &&
210 devDesc.type.connection == AudioDeviceDescription::CONNECTION_VIRTUAL) {
211 if (devDesc.type.type == AudioDeviceType::IN_SUBMIX) {
212 mRemoteSubmixIn = port;
213 } else {
214 mRemoteSubmixOut = port;
215 }
216 it = ports.erase(it);
217 } else {
218 ++it;
219 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800220 }
Mikhail Naganovae9063d2023-11-07 16:43:51 -0800221 if (mRemoteSubmixIn.has_value() != mRemoteSubmixOut.has_value()) {
222 ALOGE("%s: The configuration only has input or output remote submix device, must have both",
223 __func__);
224 mRemoteSubmixIn.reset();
225 mRemoteSubmixOut.reset();
226 }
227 if (mRemoteSubmixIn.has_value()) {
228 AudioPort connectedRSubmixIn = *mRemoteSubmixIn;
229 connectedRSubmixIn.ext.get<AudioPortExt::Tag::device>().device.address =
230 AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS;
231 ALOGD("%s: connecting remote submix input", __func__);
232 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
233 connectedRSubmixIn, &connectedRSubmixIn)));
234 // The template port for the remote submix input couldn't be "default" because it is not
235 // attached. The connected port can now be made default because we never disconnect it.
236 if (mDefaultInputPortId == -1) {
237 mDefaultInputPortId = connectedRSubmixIn.id;
238 }
239 ports.push_back(std::move(connectedRSubmixIn));
240
241 // Remote submix output must not be connected until the framework actually starts
242 // using it, however for legacy compatibility we need to provide an "augmented template"
243 // port with an address and profiles. It is obtained by connecting the output and then
244 // immediately disconnecting it. This is a cheap operation as we don't open any streams.
245 AudioPort tempConnectedRSubmixOut = *mRemoteSubmixOut;
246 tempConnectedRSubmixOut.ext.get<AudioPortExt::Tag::device>().device.address =
247 AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS;
248 ALOGD("%s: temporarily connecting and disconnecting remote submix output", __func__);
249 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
250 tempConnectedRSubmixOut, &tempConnectedRSubmixOut)));
251 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
252 tempConnectedRSubmixOut.id)));
253 tempConnectedRSubmixOut.id = mRemoteSubmixOut->id;
254 ports.push_back(std::move(tempConnectedRSubmixOut));
255 }
256
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800257 ALOGI("%s: module %s default port ids: input %d, output %d",
258 __func__, mInstance.c_str(), mDefaultInputPortId, mDefaultOutputPortId);
Mikhail Naganovae9063d2023-11-07 16:43:51 -0800259 std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()),
260 [](const auto& p) { return std::make_pair(p.id, p); });
Mikhail Naganov289468a2023-03-29 10:06:15 -0700261 RETURN_STATUS_IF_ERROR(updateRoutes());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800262 std::vector<AudioPortConfig> portConfigs;
263 RETURN_STATUS_IF_ERROR(
264 statusTFromBinderStatus(mModule->getAudioPortConfigs(&portConfigs))); // OK if empty
265 std::transform(portConfigs.begin(), portConfigs.end(),
266 std::inserter(mPortConfigs, mPortConfigs.end()),
267 [](const auto& p) { return std::make_pair(p.id, p); });
jiabin9c07faf2023-04-26 22:00:44 +0000268 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
269 std::inserter(mInitialPortConfigIds, mInitialPortConfigIds.end()),
270 [](const auto& pcPair) { return pcPair.first; });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800271 std::vector<AudioPatch> patches;
272 RETURN_STATUS_IF_ERROR(
273 statusTFromBinderStatus(mModule->getAudioPatches(&patches))); // OK if empty
274 std::transform(patches.begin(), patches.end(),
275 std::inserter(mPatches, mPatches.end()),
276 [](const auto& p) { return std::make_pair(p.id, p); });
Shunkai Yao51202502022-12-12 06:11:46 +0000277 return OK;
278}
279
280status_t DeviceHalAidl::setVoiceVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000281 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000282 if (!mModule) return NO_INIT;
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700283 if (mTelephony == nullptr) return INVALID_OPERATION;
284 ITelephony::TelecomConfig inConfig{ .voiceVolume = Float{volume} }, outConfig;
285 RETURN_STATUS_IF_ERROR(
286 statusTFromBinderStatus(mTelephony->setTelecomConfig(inConfig, &outConfig)));
287 ALOGW_IF(outConfig.voiceVolume.has_value() && volume != outConfig.voiceVolume.value().value,
288 "%s: the resulting voice volume %f is not the same as requested %f",
289 __func__, outConfig.voiceVolume.value().value, volume);
290 return OK;
Shunkai Yao51202502022-12-12 06:11:46 +0000291}
292
293status_t DeviceHalAidl::setMasterVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000294 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000295 if (!mModule) return NO_INIT;
296 return statusTFromBinderStatus(mModule->setMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000297}
298
299status_t DeviceHalAidl::getMasterVolume(float *volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000300 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000301 if (!mModule) return NO_INIT;
302 return statusTFromBinderStatus(mModule->getMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000303}
304
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000305status_t DeviceHalAidl::setMode(audio_mode_t mode) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000306 TIME_CHECK();
307 if (!mModule) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000308 AudioMode audioMode = VALUE_OR_FATAL(::aidl::android::legacy2aidl_audio_mode_t_AudioMode(mode));
Mikhail Naganov1fba38c2023-05-03 17:45:36 -0700309 if (mTelephony != nullptr) {
310 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mTelephony->switchAudioMode(audioMode)));
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000311 }
312 return statusTFromBinderStatus(mModule->updateAudioMode(audioMode));
Shunkai Yao51202502022-12-12 06:11:46 +0000313}
314
315status_t DeviceHalAidl::setMicMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000316 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000317 if (!mModule) return NO_INIT;
318 return statusTFromBinderStatus(mModule->setMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000319}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000320
Shunkai Yao51202502022-12-12 06:11:46 +0000321status_t DeviceHalAidl::getMicMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000322 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000323 if (!mModule) return NO_INIT;
324 return statusTFromBinderStatus(mModule->getMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000325}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000326
Shunkai Yao51202502022-12-12 06:11:46 +0000327status_t DeviceHalAidl::setMasterMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000328 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000329 if (!mModule) return NO_INIT;
330 return statusTFromBinderStatus(mModule->setMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000331}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000332
Shunkai Yao51202502022-12-12 06:11:46 +0000333status_t DeviceHalAidl::getMasterMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000334 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000335 if (!mModule) return NO_INIT;
336 return statusTFromBinderStatus(mModule->getMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000337}
338
Mikhail Naganovccc82112023-04-27 18:14:15 -0700339status_t DeviceHalAidl::setParameters(const String8& kvPairs) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000340 if (!mModule) return NO_INIT;
Mikhail Naganovccc82112023-04-27 18:14:15 -0700341 AudioParameter parameters(kvPairs);
342 ALOGD("%s: parameters: \"%s\"", __func__, parameters.toString().c_str());
343
344 if (status_t status = filterAndUpdateBtA2dpParameters(parameters); status != OK) {
345 ALOGW("%s: filtering or updating BT A2DP parameters failed: %d", __func__, status);
346 }
347 if (status_t status = filterAndUpdateBtHfpParameters(parameters); status != OK) {
348 ALOGW("%s: filtering or updating BT HFP parameters failed: %d", __func__, status);
349 }
350 if (status_t status = filterAndUpdateBtLeParameters(parameters); status != OK) {
351 ALOGW("%s: filtering or updating BT LE parameters failed: %d", __func__, status);
352 }
353 if (status_t status = filterAndUpdateBtScoParameters(parameters); status != OK) {
354 ALOGW("%s: filtering or updating BT SCO parameters failed: %d", __func__, status);
355 }
Mikhail Naganove92c34b2023-05-31 14:24:48 -0700356 if (status_t status = filterAndUpdateScreenParameters(parameters); status != OK) {
357 ALOGW("%s: filtering or updating screen parameters failed: %d", __func__, status);
358 }
Mikhail Naganovb9a81312023-07-18 13:55:34 -0700359 if (status_t status = filterAndUpdateTelephonyParameters(parameters); status != OK) {
360 ALOGW("%s: filtering or updating telephony parameters failed: %d", __func__, status);
361 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700362 return parseAndSetVendorParameters(mVendorExt, mModule, parameters);
Shunkai Yao51202502022-12-12 06:11:46 +0000363}
364
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700365status_t DeviceHalAidl::getParameters(const String8& keys, String8 *values) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000366 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000367 if (!mModule) return NO_INIT;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700368 if (values == nullptr) {
369 return BAD_VALUE;
370 }
371 AudioParameter parameterKeys(keys), result;
372 if (status_t status = filterAndRetrieveBtA2dpParameters(parameterKeys, &result); status != OK) {
373 ALOGW("%s: filtering or retrieving BT A2DP parameters failed: %d", __func__, status);
374 }
375 *values = result.toString();
376 return parseAndGetVendorParameters(mVendorExt, mModule, parameterKeys, values);
Shunkai Yao51202502022-12-12 06:11:46 +0000377}
378
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800379namespace {
380
381class Cleanup {
382 public:
383 typedef void (DeviceHalAidl::*Cleaner)(int32_t);
384
385 Cleanup(DeviceHalAidl* device, Cleaner cleaner, int32_t id) :
386 mDevice(device), mCleaner(cleaner), mId(id) {}
387 ~Cleanup() { clean(); }
388 void clean() {
389 if (mDevice != nullptr) (mDevice->*mCleaner)(mId);
390 disarm();
391 }
392 void disarm() { mDevice = nullptr; }
393
394 private:
395 DeviceHalAidl* mDevice;
396 const Cleaner mCleaner;
397 const int32_t mId;
398};
399
400} // namespace
401
402// Since the order of container elements destruction is unspecified,
403// ensure that cleanups are performed from the most recent one and upwards.
404// This is the same as if there were individual Cleanup instances on the stack,
405// however the bonus is that we can disarm all of them with just one statement.
406class DeviceHalAidl::Cleanups : public std::forward_list<Cleanup> {
407 public:
408 ~Cleanups() { for (auto& c : *this) c.clean(); }
409 void disarmAll() { for (auto& c : *this) c.disarm(); }
410};
411
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800412status_t DeviceHalAidl::getInputBufferSize(const struct audio_config* config, size_t* size) {
413 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
414 if (size == nullptr) return BAD_VALUE;
415 TIME_CHECK();
416 if (!mModule) return NO_INIT;
417 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
418 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
419 AudioDevice aidlDevice;
420 aidlDevice.type.type = AudioDeviceType::IN_DEFAULT;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800421 AudioSource aidlSource = AudioSource::DEFAULT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800422 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
423 AudioPortConfig mixPortConfig;
424 Cleanups cleanups;
425 audio_config writableConfig = *config;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700426 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800427 RETURN_STATUS_IF_ERROR(prepareToOpenStream(0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700428 &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800429 *size = aidlConfig.frameCount *
430 getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
431 // Do not disarm cleanups to release temporary port configs.
432 return OK;
433}
434
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800435status_t DeviceHalAidl::prepareToOpenStream(
436 int32_t aidlHandle, const AudioDevice& aidlDevice, const AudioIoFlags& aidlFlags,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800437 AudioSource aidlSource, struct audio_config* config,
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800438 Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700439 AudioPatch* aidlPatch) {
440 ALOGD("%p %s::%s: handle %d, device %s, flags %s, source %s, config %s, mix port config %s",
441 this, getClassName().c_str(), __func__, aidlHandle, aidlDevice.toString().c_str(),
442 aidlFlags.toString().c_str(), toString(aidlSource).c_str(),
443 aidlConfig->toString().c_str(), mixPortConfig->toString().c_str());
jiabin9c07faf2023-04-26 22:00:44 +0000444 resetUnusedPatchesAndPortConfigs();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800445 const bool isInput = aidlFlags.getTag() == AudioIoFlags::Tag::input;
446 // Find / create AudioPortConfigs for the device port and the mix port,
447 // then find / create a patch between them, and open a stream on the mix port.
448 AudioPortConfig devicePortConfig;
449 bool created = false;
jiabin9c07faf2023-04-26 22:00:44 +0000450 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, aidlConfig,
451 &devicePortConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800452 if (created) {
453 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
454 }
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800455 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*aidlConfig, aidlFlags, aidlHandle, aidlSource,
Mikhail Naganov289468a2023-03-29 10:06:15 -0700456 std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800457 if (created) {
458 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
459 }
460 setConfigFromPortConfig(aidlConfig, *mixPortConfig);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800461 if (isInput) {
462 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700463 {devicePortConfig.id}, {mixPortConfig->id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800464 } else {
465 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700466 {mixPortConfig->id}, {devicePortConfig.id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800467 }
468 if (created) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700469 cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, aidlPatch->id);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800470 }
471 if (aidlConfig->frameCount <= 0) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700472 aidlConfig->frameCount = aidlPatch->minimumStreamBufferSizeFrames;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800473 }
474 *config = VALUE_OR_RETURN_STATUS(
475 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(*aidlConfig, isInput));
476 return OK;
477}
478
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800479namespace {
480
481class StreamCallbackBase {
482 protected:
483 explicit StreamCallbackBase(const sp<CallbackBroker>& broker) : mBroker(broker) {}
484 public:
485 void* getCookie() const { return mCookie; }
486 void setCookie(void* cookie) { mCookie = cookie; }
487 sp<CallbackBroker> getBroker() const {
488 if (void* cookie = mCookie; cookie != nullptr) return mBroker.promote();
489 return nullptr;
490 }
491 private:
492 const wp<CallbackBroker> mBroker;
493 std::atomic<void*> mCookie;
494};
495
496template<class C>
497class StreamCallbackBaseHelper {
498 protected:
499 explicit StreamCallbackBaseHelper(const StreamCallbackBase& base) : mBase(base) {}
500 sp<C> getCb(const sp<CallbackBroker>& broker, void* cookie);
501 using CbRef = const sp<C>&;
502 ndk::ScopedAStatus runCb(const std::function<void(CbRef cb)>& f) {
503 if (auto cb = getCb(mBase.getBroker(), mBase.getCookie()); cb != nullptr) f(cb);
504 return ndk::ScopedAStatus::ok();
505 }
506 private:
507 const StreamCallbackBase& mBase;
508};
509
510template<>
511sp<StreamOutHalInterfaceCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>::getCb(
512 const sp<CallbackBroker>& broker, void* cookie) {
513 if (broker != nullptr) return broker->getStreamOutCallback(cookie);
514 return nullptr;
515}
516
517template<>
518sp<StreamOutHalInterfaceEventCallback>
519StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::getCb(
520 const sp<CallbackBroker>& broker, void* cookie) {
521 if (broker != nullptr) return broker->getStreamOutEventCallback(cookie);
522 return nullptr;
523}
524
525template<>
526sp<StreamOutHalInterfaceLatencyModeCallback>
527StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::getCb(
528 const sp<CallbackBroker>& broker, void* cookie) {
529 if (broker != nullptr) return broker->getStreamOutLatencyModeCallback(cookie);
530 return nullptr;
531}
532
533/*
534Note on the callback ownership.
535
536In the Binder ownership model, the server implementation is kept alive
537as long as there is any client (proxy object) alive. This is done by
538incrementing the refcount of the server-side object by the Binder framework.
539When it detects that the last client is gone, it decrements the refcount back.
540
541Thus, it is not needed to keep any references to StreamCallback on our
542side (after we have sent an instance to the client), because we are
543the server-side. The callback object will be kept alive as long as the HAL server
544holds a strong ref to IStreamCallback proxy.
545*/
546
547class OutputStreamCallbackAidl : public StreamCallbackBase,
548 public StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>,
549 public ::aidl::android::hardware::audio::core::BnStreamCallback {
550 public:
551 explicit OutputStreamCallbackAidl(const sp<CallbackBroker>& broker)
552 : StreamCallbackBase(broker),
553 StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>(
554 *static_cast<StreamCallbackBase*>(this)) {}
555 ndk::ScopedAStatus onTransferReady() override {
556 return runCb([](CbRef cb) { cb->onWriteReady(); });
557 }
558 ndk::ScopedAStatus onError() override {
559 return runCb([](CbRef cb) { cb->onError(); });
560 }
561 ndk::ScopedAStatus onDrainReady() override {
562 return runCb([](CbRef cb) { cb->onDrainReady(); });
563 }
564};
565
566class OutputStreamEventCallbackAidl :
567 public StreamCallbackBase,
568 public StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>,
569 public StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>,
570 public ::aidl::android::hardware::audio::core::BnStreamOutEventCallback {
571 public:
572 explicit OutputStreamEventCallbackAidl(const sp<CallbackBroker>& broker)
573 : StreamCallbackBase(broker),
574 StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>(
575 *static_cast<StreamCallbackBase*>(this)),
576 StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>(
577 *static_cast<StreamCallbackBase*>(this)) {}
578 ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& in_audioMetadata) override {
579 std::basic_string<uint8_t> halMetadata(in_audioMetadata.begin(), in_audioMetadata.end());
580 return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb(
581 [&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); });
582 }
583 ndk::ScopedAStatus onRecommendedLatencyModeChanged(
584 const std::vector<AudioLatencyMode>& in_modes) override {
585 auto halModes = VALUE_OR_FATAL(
586 ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
587 in_modes,
588 ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
589 return StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::runCb(
590 [&halModes](auto cb) { cb->onRecommendedLatencyModeChanged(halModes); });
591 }
592};
593
594} // namespace
595
Mikhail Naganov31d46652023-01-10 18:29:25 +0000596status_t DeviceHalAidl::openOutputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800597 audio_io_handle_t handle, audio_devices_t devices,
598 audio_output_flags_t flags, struct audio_config* config,
599 const char* address,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000600 sp<StreamOutHalInterface>* outStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800601 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000602 if (!outStream || !config) {
603 return BAD_VALUE;
604 }
605 TIME_CHECK();
606 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800607 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
608 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
609 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
610 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, false /*isInput*/));
611 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
612 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
613 int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
614 ::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
615 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
616 AudioPortConfig mixPortConfig;
617 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700618 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800619 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
620 AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700621 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800622 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
623 args.portConfigId = mixPortConfig.id;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800624 const bool isOffload = isBitPositionFlagSet(
625 aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD);
626 std::shared_ptr<OutputStreamCallbackAidl> streamCb;
627 if (isOffload) {
628 streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
629 }
630 auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
631 if (isOffload) {
632 args.offloadInfo = aidlConfig.offloadInfo;
633 args.callback = streamCb;
634 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800635 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800636 args.eventCallback = eventCb;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800637 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
638 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800639 StreamContextAidl context(ret.desc, isOffload);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800640 if (!context.isValid()) {
641 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
642 __func__, ret.desc.toString().c_str());
643 return NO_INIT;
644 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700645 *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700646 std::move(ret.stream), mVendorExt, this /*callbackBroker*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700647 mStreams.insert(std::pair(*outStream, aidlPatch.id));
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800648 void* cbCookie = (*outStream).get();
649 {
650 std::lock_guard l(mLock);
651 mCallbacks.emplace(cbCookie, Callbacks{});
652 }
653 if (streamCb) streamCb->setCookie(cbCookie);
654 eventCb->setCookie(cbCookie);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800655 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000656 return OK;
657}
658
Mikhail Naganov31d46652023-01-10 18:29:25 +0000659status_t DeviceHalAidl::openInputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800660 audio_io_handle_t handle, audio_devices_t devices,
661 struct audio_config* config, audio_input_flags_t flags,
662 const char* address, audio_source_t source,
663 audio_devices_t outputDevice, const char* outputDeviceAddress,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000664 sp<StreamInHalInterface>* inStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800665 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000666 if (!inStream || !config) {
667 return BAD_VALUE;
668 }
669 TIME_CHECK();
670 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800671 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
672 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
673 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
674 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
675 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
676 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
677 int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
678 ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
679 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
680 AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
681 ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
682 AudioPortConfig mixPortConfig;
683 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700684 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800685 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700686 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800687 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
688 args.portConfigId = mixPortConfig.id;
689 RecordTrackMetadata aidlTrackMetadata{
690 .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
691 if (outputDevice != AUDIO_DEVICE_NONE) {
692 aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
693 ::aidl::android::legacy2aidl_audio_device_AudioDevice(
694 outputDevice, outputDeviceAddress));
695 }
696 args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
697 args.bufferSizeFrames = aidlConfig.frameCount;
698 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
699 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800700 StreamContextAidl context(ret.desc, false /*isAsynchronous*/);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800701 if (!context.isValid()) {
702 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
703 __func__, ret.desc.toString().c_str());
704 return NO_INIT;
705 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700706 *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700707 std::move(ret.stream), mVendorExt, this /*micInfoProvider*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700708 mStreams.insert(std::pair(*inStream, aidlPatch.id));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800709 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000710 return OK;
711}
712
713status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
714 *supportsPatches = true;
715 return OK;
716}
717
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800718status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
719 const struct audio_port_config* sources,
720 unsigned int num_sinks,
721 const struct audio_port_config* sinks,
722 audio_patch_handle_t* patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800723 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000724 TIME_CHECK();
725 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800726 if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
727 sources == nullptr || sinks == nullptr || patch == nullptr) {
728 return BAD_VALUE;
729 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800730 // When the patch handle (*patch) is AUDIO_PATCH_HANDLE_NONE, it means
731 // the framework wants to create a new patch. The handle has to be generated
732 // by the HAL. Since handles generated this way can only be unique within
733 // a HAL module, the framework generates a globally unique handle, and maps
734 // it on the <HAL module, patch handle> pair.
735 // When the patch handle is set, it meant the framework intends to update
736 // an existing patch.
737 //
738 // This behavior corresponds to HAL module behavior, with the only difference
739 // that the HAL module uses `int32_t` for patch IDs. The following assert ensures
740 // that both the framework and the HAL use the same value for "no ID":
741 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
742 int32_t halPatchId = static_cast<int32_t>(*patch);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800743
744 // Upon conversion, mix port configs contain audio configuration, while
745 // device port configs contain device address. This data is used to find
746 // or create HAL configs.
747 std::vector<AudioPortConfig> aidlSources, aidlSinks;
748 for (unsigned int i = 0; i < num_sources; ++i) {
749 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
750 sources[i].role, sources[i].type)) ==
751 ::aidl::android::AudioPortDirection::INPUT;
752 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
753 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
754 sources[i], isInput, 0)));
755 }
756 for (unsigned int i = 0; i < num_sinks; ++i) {
757 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
758 sinks[i].role, sinks[i].type)) ==
759 ::aidl::android::AudioPortDirection::INPUT;
760 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
761 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
762 sinks[i], isInput, 0)));
763 }
764 Cleanups cleanups;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800765 auto existingPatchIt = halPatchId != 0 ? mPatches.find(halPatchId): mPatches.end();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800766 AudioPatch aidlPatch;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800767 if (existingPatchIt != mPatches.end()) {
768 aidlPatch = existingPatchIt->second;
769 aidlPatch.sourcePortConfigIds.clear();
770 aidlPatch.sinkPortConfigIds.clear();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800771 }
Mikhail Naganov02038012023-09-08 12:38:14 -0700772 // The IDs will be found by 'fillPortConfigs', however the original 'aidlSources' and
773 // 'aidlSinks' will not be updated because 'setAudioPatch' only needs IDs. Here we log
774 // the source arguments, where only the audio configuration and device specifications
775 // are relevant.
776 ALOGD("%s: [disregard IDs] sources: %s, sinks: %s",
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800777 __func__, ::android::internal::ToString(aidlSources).c_str(),
778 ::android::internal::ToString(aidlSinks).c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800779 auto fillPortConfigs = [&](
Mikhail Naganov289468a2023-03-29 10:06:15 -0700780 const std::vector<AudioPortConfig>& configs,
781 const std::set<int32_t>& destinationPortIds,
782 std::vector<int32_t>* ids, std::set<int32_t>* portIds) -> status_t {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800783 for (const auto& s : configs) {
784 AudioPortConfig portConfig;
785 bool created = false;
Mikhail Naganov289468a2023-03-29 10:06:15 -0700786 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
787 s, destinationPortIds, &portConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800788 if (created) {
789 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, portConfig.id);
790 }
791 ids->push_back(portConfig.id);
Mikhail Naganov289468a2023-03-29 10:06:15 -0700792 if (portIds != nullptr) {
793 portIds->insert(portConfig.portId);
794 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800795 }
796 return OK;
797 };
Mikhail Naganov289468a2023-03-29 10:06:15 -0700798 // When looking up port configs, the destinationPortId is only used for mix ports.
799 // Thus, we process device port configs first, and look up the destination port ID from them.
800 bool sourceIsDevice = std::any_of(aidlSources.begin(), aidlSources.end(),
801 [](const auto& config) { return config.ext.getTag() == AudioPortExt::device; });
802 const std::vector<AudioPortConfig>& devicePortConfigs =
803 sourceIsDevice ? aidlSources : aidlSinks;
804 std::vector<int32_t>* devicePortConfigIds =
805 sourceIsDevice ? &aidlPatch.sourcePortConfigIds : &aidlPatch.sinkPortConfigIds;
806 const std::vector<AudioPortConfig>& mixPortConfigs =
807 sourceIsDevice ? aidlSinks : aidlSources;
808 std::vector<int32_t>* mixPortConfigIds =
809 sourceIsDevice ? &aidlPatch.sinkPortConfigIds : &aidlPatch.sourcePortConfigIds;
810 std::set<int32_t> devicePortIds;
811 RETURN_STATUS_IF_ERROR(fillPortConfigs(
812 devicePortConfigs, std::set<int32_t>(), devicePortConfigIds, &devicePortIds));
813 RETURN_STATUS_IF_ERROR(fillPortConfigs(
814 mixPortConfigs, devicePortIds, mixPortConfigIds, nullptr));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800815 if (existingPatchIt != mPatches.end()) {
816 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
817 mModule->setAudioPatch(aidlPatch, &aidlPatch)));
818 existingPatchIt->second = aidlPatch;
819 } else {
820 bool created = false;
821 RETURN_STATUS_IF_ERROR(findOrCreatePatch(aidlPatch, &aidlPatch, &created));
822 // Since no cleanup of the patch is needed, 'created' is ignored.
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800823 halPatchId = aidlPatch.id;
824 *patch = static_cast<audio_patch_handle_t>(halPatchId);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800825 }
826 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000827 return OK;
828}
829
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800830status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800831 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000832 TIME_CHECK();
833 if (!mModule) return NO_INIT;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800834 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
835 if (patch == AUDIO_PATCH_HANDLE_NONE) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800836 return BAD_VALUE;
837 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800838 int32_t halPatchId = static_cast<int32_t>(patch);
839 auto patchIt = mPatches.find(halPatchId);
840 if (patchIt == mPatches.end()) {
841 ALOGE("%s: patch with id %d not found", __func__, halPatchId);
842 return BAD_VALUE;
843 }
844 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->resetAudioPatch(halPatchId)));
845 mPatches.erase(patchIt);
Shunkai Yao51202502022-12-12 06:11:46 +0000846 return OK;
847}
848
Mikhail Naganove93a0862023-03-15 17:06:59 -0700849status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
850 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000851 TIME_CHECK();
852 if (!mModule) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700853 if (port == nullptr) {
854 return BAD_VALUE;
855 }
856 audio_port_v7 portV7;
857 audio_populate_audio_port_v7(port, &portV7);
858 RETURN_STATUS_IF_ERROR(getAudioPort(&portV7));
859 return audio_populate_audio_port(&portV7, port) ? OK : BAD_VALUE;
860}
861
862status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
863 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
864 TIME_CHECK();
865 if (!mModule) return NO_INIT;
866 if (port == nullptr) {
867 return BAD_VALUE;
868 }
869 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
870 ::aidl::android::AudioPortDirection::INPUT;
871 auto aidlPort = VALUE_OR_RETURN_STATUS(
872 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
873 if (aidlPort.ext.getTag() != AudioPortExt::device) {
874 ALOGE("%s: provided port is not a device port (module %s): %s",
875 __func__, mInstance.c_str(), aidlPort.toString().c_str());
876 return BAD_VALUE;
877 }
878 const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
879 // It seems that we don't have to call HAL since all valid ports have been added either
880 // during initialization, or while handling connection of an external device.
881 auto portsIt = findPort(matchDevice);
882 if (portsIt == mPorts.end()) {
883 ALOGE("%s: device port for device %s is not found in the module %s",
884 __func__, matchDevice.toString().c_str(), mInstance.c_str());
885 return BAD_VALUE;
886 }
887 const int32_t fwkId = aidlPort.id;
888 aidlPort = portsIt->second;
889 aidlPort.id = fwkId;
890 *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
891 aidlPort, isInput));
892 return OK;
893}
894
jiabin12537fc2023-10-12 17:56:08 +0000895status_t DeviceHalAidl::getAudioMixPort(const struct audio_port_v7 *devicePort,
896 struct audio_port_v7 *mixPort) {
897 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
898 if (devicePort->type != AUDIO_PORT_TYPE_DEVICE) {
899 return BAD_VALUE;
900 }
901 if (mixPort->type != AUDIO_PORT_TYPE_MIX) {
902 return BAD_VALUE;
903 }
904 const int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
905 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(mixPort->ext.mix.handle));
906 auto it = findPortConfig(std::nullopt /*config*/, std::nullopt/*flags*/, aidlHandle);
907 if (it == mPortConfigs.end()) {
908 ALOGE("%s, cannot find mix port config for handle=%u", __func__, aidlHandle);
909 return BAD_VALUE;
910 }
911 AudioPort port;
912 if (status_t status = getAudioPort(it->second.portId, &port); status != NO_ERROR) {
913 return status;
914 }
915 const bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
916 mixPort->role, mixPort->type)) == ::aidl::android::AudioPortDirection::INPUT;
917 *mixPort = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
918 port, isInput));
919 return NO_ERROR;
920}
921
Mikhail Naganove93a0862023-03-15 17:06:59 -0700922status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
923 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
924 TIME_CHECK();
925 if (!mModule) return NO_INIT;
926 if (config == nullptr) {
927 return BAD_VALUE;
928 }
929 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
930 config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
931 AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
932 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
933 *config, isInput, 0 /*portId*/));
934 AudioPortConfig portConfig;
935 bool created = false;
Mikhail Naganov289468a2023-03-29 10:06:15 -0700936 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
937 requestedPortConfig, std::set<int32_t>(), &portConfig, &created));
Shunkai Yao51202502022-12-12 06:11:46 +0000938 return OK;
939}
940
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800941MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
942 if (mMicrophones.status == Microphones::Status::UNKNOWN) {
943 TIME_CHECK();
944 std::vector<MicrophoneInfo> aidlInfo;
945 status_t status = statusTFromBinderStatus(mModule->getMicrophones(&aidlInfo));
946 if (status == OK) {
947 mMicrophones.status = Microphones::Status::QUERIED;
948 mMicrophones.info = std::move(aidlInfo);
949 } else if (status == INVALID_OPERATION) {
950 mMicrophones.status = Microphones::Status::NOT_SUPPORTED;
951 } else {
952 ALOGE("%s: Unexpected status from 'IModule.getMicrophones': %d", __func__, status);
953 return {};
954 }
955 }
956 if (mMicrophones.status == Microphones::Status::QUERIED) {
957 return &mMicrophones.info;
958 }
959 return {}; // NOT_SUPPORTED
960}
961
Shunkai Yao51202502022-12-12 06:11:46 +0000962status_t DeviceHalAidl::getMicrophones(
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800963 std::vector<audio_microphone_characteristic_t>* microphones) {
964 if (!microphones) {
965 return BAD_VALUE;
966 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000967 TIME_CHECK();
968 if (!mModule) return NO_INIT;
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800969 auto staticInfo = getMicrophoneInfo();
970 if (!staticInfo) return INVALID_OPERATION;
971 std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
972 emptyDynamicInfo.reserve(staticInfo->size());
973 std::transform(staticInfo->begin(), staticInfo->end(), std::back_inserter(emptyDynamicInfo),
974 [](const auto& info) { return MicrophoneDynamicInfo{ .id = info.id }; });
975 *microphones = VALUE_OR_RETURN_STATUS(
976 ::aidl::android::convertContainers<std::vector<audio_microphone_characteristic_t>>(
977 *staticInfo, emptyDynamicInfo,
978 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t)
979 );
Shunkai Yao51202502022-12-12 06:11:46 +0000980 return OK;
981}
982
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700983status_t DeviceHalAidl::addDeviceEffect(
984 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
985 TIME_CHECK();
986 if (!mModule) return NO_INIT;
Shunkai Yao51202502022-12-12 06:11:46 +0000987 if (!effect) {
988 return BAD_VALUE;
989 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700990 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
991 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
992 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
993 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
994 *device, isInput, 0));
995 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
996 ALOGE("%s: provided port config is not a device port config: %s",
997 __func__, requestedPortConfig.toString().c_str());
998 return BAD_VALUE;
999 }
1000 AudioPortConfig devicePortConfig;
1001 bool created;
1002 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
1003 requestedPortConfig, {} /*destinationPortIds*/, &devicePortConfig, &created));
1004 Cleanups cleanups;
1005 if (created) {
1006 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
1007 }
1008 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
1009 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->addDeviceEffect(
1010 devicePortConfig.id, aidlEffect->getIEffect())));
1011 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +00001012 return OK;
1013}
Mikhail Naganova82a69d2023-06-14 16:31:32 -07001014status_t DeviceHalAidl::removeDeviceEffect(
1015 const struct audio_port_config *device, sp<EffectHalInterface> effect) {
1016 TIME_CHECK();
1017 if (!mModule) return NO_INIT;
Shunkai Yao51202502022-12-12 06:11:46 +00001018 if (!effect) {
1019 return BAD_VALUE;
1020 }
Mikhail Naganova82a69d2023-06-14 16:31:32 -07001021 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
1022 device->role, device->type)) == ::aidl::android::AudioPortDirection::INPUT;
1023 auto requestedPortConfig = VALUE_OR_RETURN_STATUS(
1024 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
1025 *device, isInput, 0));
1026 if (requestedPortConfig.ext.getTag() != AudioPortExt::Tag::device) {
1027 ALOGE("%s: provided port config is not a device port config: %s",
1028 __func__, requestedPortConfig.toString().c_str());
1029 return BAD_VALUE;
1030 }
1031 auto existingPortConfigIt = findPortConfig(
1032 requestedPortConfig.ext.get<AudioPortExt::Tag::device>().device);
1033 if (existingPortConfigIt == mPortConfigs.end()) {
1034 ALOGE("%s: could not find a configured device port for the config %s",
1035 __func__, requestedPortConfig.toString().c_str());
1036 return BAD_VALUE;
1037 }
1038 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
1039 return statusTFromBinderStatus(mModule->removeDeviceEffect(
1040 existingPortConfigIt->first, aidlEffect->getIEffect()));
Shunkai Yao51202502022-12-12 06:11:46 +00001041}
1042
1043status_t DeviceHalAidl::getMmapPolicyInfos(
David Li9cf5e622023-03-21 00:51:10 +08001044 media::audio::common::AudioMMapPolicyType policyType,
1045 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
Mikhail Naganov31d46652023-01-10 18:29:25 +00001046 TIME_CHECK();
Mikhail Naganov25bc9a22023-04-21 18:48:16 -07001047 AudioMMapPolicyType mmapPolicyType = VALUE_OR_RETURN_STATUS(
1048 cpp2ndk_AudioMMapPolicyType(policyType));
David Li9cf5e622023-03-21 00:51:10 +08001049
1050 std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
1051
1052 if (status_t status = statusTFromBinderStatus(
1053 mModule->getMmapPolicyInfos(mmapPolicyType, &mmapPolicyInfos)); status != OK) {
1054 return status;
1055 }
1056
1057 *policyInfos = VALUE_OR_RETURN_STATUS(
1058 convertContainer<std::vector<media::audio::common::AudioMMapPolicyInfo>>(
1059 mmapPolicyInfos, ndk2cpp_AudioMMapPolicyInfo));
Shunkai Yao51202502022-12-12 06:11:46 +00001060 return OK;
1061}
1062
1063int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganov31d46652023-01-10 18:29:25 +00001064 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +08001065 int32_t mixerBurstCount = 0;
1066 if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
1067 return mixerBurstCount;
1068 }
1069 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +00001070}
1071
1072int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganov31d46652023-01-10 18:29:25 +00001073 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +08001074 int32_t hardwareBurstMinUsec = 0;
1075 if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
1076 return hardwareBurstMinUsec;
1077 }
1078 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +00001079}
1080
1081error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganov31d46652023-01-10 18:29:25 +00001082 TIME_CHECK();
Mikhail Naganov08a62ab2023-03-14 17:11:51 -07001083 if (!mModule) return NO_INIT;
1084 int32_t aidlHwAvSync;
1085 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
1086 return VALUE_OR_RETURN_STATUS(
1087 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +00001088}
1089
Mikhail Naganovfab697c2023-01-11 19:33:13 +00001090status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
1091 TIME_CHECK();
1092 if (!mModule) return NO_INIT;
1093 return mModule->dump(fd, Args(args).args(), args.size());
David Li9cf5e622023-03-21 00:51:10 +08001094}
Shunkai Yao51202502022-12-12 06:11:46 +00001095
Eric Laurent7af6ee72023-06-29 11:44:54 +02001096status_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
Mikhail Naganov31d46652023-01-10 18:29:25 +00001097 TIME_CHECK();
Mikhail Naganov3ac95c92023-04-12 13:14:30 -07001098 if (!mModule) return NO_INIT;
1099 if (supports == nullptr) {
1100 return BAD_VALUE;
1101 }
1102 return statusTFromBinderStatus(mModule->supportsVariableLatency(supports));
Shunkai Yao51202502022-12-12 06:11:46 +00001103}
Mikhail Naganov31d46652023-01-10 18:29:25 +00001104
Vlad Popa03bd5bc2023-01-17 16:16:51 +01001105status_t DeviceHalAidl::getSoundDoseInterface(const std::string& module,
1106 ::ndk::SpAIBinder* soundDoseBinder) {
1107 TIME_CHECK();
1108 if (!mModule) return NO_INIT;
1109 if (mSoundDose == nullptr) {
1110 ndk::ScopedAStatus status = mModule->getSoundDose(&mSoundDose);
1111 if (!status.isOk()) {
1112 ALOGE("%s failed to return the sound dose interface for module %s: %s",
1113 __func__,
1114 module.c_str(),
1115 status.getDescription().c_str());
1116 return BAD_VALUE;
1117 }
1118 }
1119 *soundDoseBinder = mSoundDose->asBinder();
1120 ALOGI("%s using audio AIDL HAL sound dose interface", __func__);
1121
1122 return OK;
1123}
jiabin872de702023-04-27 22:04:31 +00001124
1125status_t DeviceHalAidl::prepareToDisconnectExternalDevice(const struct audio_port_v7* port) {
1126 // There is not AIDL API defined for `prepareToDisconnectExternalDevice`.
1127 // Call `setConnectedState` instead.
1128 // TODO(b/279824103): call prepareToDisconnectExternalDevice when it is added.
Mikhail Naganov66907492023-09-11 17:22:03 -07001129 if (const status_t status = setConnectedState(port, false /*connected*/); status == NO_ERROR) {
jiabin872de702023-04-27 22:04:31 +00001130 mDeviceDisconnectionNotified.insert(port->id);
1131 }
Mikhail Naganov66907492023-09-11 17:22:03 -07001132 // Return that there was no error as otherwise the disconnection procedure will not be
1133 // considered complete for upper layers, and 'setConnectedState' will not be called again.
1134 return NO_ERROR;
jiabin872de702023-04-27 22:04:31 +00001135}
1136
Mikhail Naganove93a0862023-03-15 17:06:59 -07001137status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
Mikhail Naganovae9063d2023-11-07 16:43:51 -08001138 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganove93a0862023-03-15 17:06:59 -07001139 TIME_CHECK();
1140 if (!mModule) return NO_INIT;
1141 if (port == nullptr) {
1142 return BAD_VALUE;
1143 }
jiabin872de702023-04-27 22:04:31 +00001144 if (!connected && mDeviceDisconnectionNotified.erase(port->id) > 0) {
1145 // For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
1146 // and then call `setConnectedState`. However, there is no API for
1147 // `prepareToDisconnectExternalDevice` yet. In that case, `setConnectedState` will be
1148 // called when calling `prepareToDisconnectExternalDevice`. Do not call to the HAL if
1149 // previous call is successful. Also remove the cache here to avoid a large cache after
1150 // a long run.
1151 return NO_ERROR;
1152 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001153 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
1154 ::aidl::android::AudioPortDirection::INPUT;
1155 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
1156 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
1157 if (aidlPort.ext.getTag() != AudioPortExt::device) {
1158 ALOGE("%s: provided port is not a device port (module %s): %s",
1159 __func__, mInstance.c_str(), aidlPort.toString().c_str());
1160 return BAD_VALUE;
1161 }
1162 if (connected) {
1163 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
Mikhail Naganovae9063d2023-11-07 16:43:51 -08001164 std::optional<AudioPort> templatePort;
1165 auto erasePortAfterConnectionIt = mPorts.end();
1166 // Connection of remote submix out with address "0" is a special case. Since there is
1167 // already an "augmented template" port with this address in mPorts, we need to replace
1168 // it with a connected port.
1169 // Connection of remote submix outs with any other address is done as usual except that
1170 // the template port is in `mRemoteSubmixOut`.
1171 if (mRemoteSubmixOut.has_value() &&
1172 matchDevice.type.type == AudioDeviceType::OUT_SUBMIX) {
1173 if (matchDevice.address == AudioDeviceAddress::make<AudioDeviceAddress::id>(
1174 AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS)) {
1175 erasePortAfterConnectionIt = findPort(matchDevice);
1176 }
1177 templatePort = mRemoteSubmixOut;
1178 } else if (mRemoteSubmixIn.has_value() &&
1179 matchDevice.type.type == AudioDeviceType::IN_SUBMIX) {
1180 templatePort = mRemoteSubmixIn;
Mikhail Naganov02038012023-09-08 12:38:14 -07001181 } else {
Mikhail Naganovae9063d2023-11-07 16:43:51 -08001182 // Reset the device address to find the "template" port.
1183 matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
1184 }
1185 if (!templatePort.has_value()) {
1186 auto portsIt = findPort(matchDevice);
1187 if (portsIt == mPorts.end()) {
1188 // Since 'setConnectedState' is called for all modules, it is normal when the device
1189 // port not found in every one of them.
1190 return BAD_VALUE;
1191 } else {
1192 ALOGD("%s: device port for device %s found in the module %s",
1193 __func__, matchDevice.toString().c_str(), mInstance.c_str());
1194 }
1195 templatePort = portsIt->second;
Mikhail Naganove93a0862023-03-15 17:06:59 -07001196 }
Mikhail Naganov66907492023-09-11 17:22:03 -07001197 resetUnusedPatchesAndPortConfigs();
Mikhail Naganovae9063d2023-11-07 16:43:51 -08001198
Mikhail Naganove93a0862023-03-15 17:06:59 -07001199 // Use the ID of the "template" port, use all the information from the provided port.
Mikhail Naganovae9063d2023-11-07 16:43:51 -08001200 aidlPort.id = templatePort->id;
Mikhail Naganove93a0862023-03-15 17:06:59 -07001201 AudioPort connectedPort;
1202 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
1203 aidlPort, &connectedPort)));
1204 const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
1205 LOG_ALWAYS_FATAL_IF(!inserted,
1206 "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
1207 __func__, mInstance.c_str(), connectedPort.toString().c_str(),
1208 it->second.toString().c_str());
Mikhail Naganov892f7612023-09-15 18:55:39 -07001209 mConnectedPorts[connectedPort.id] = false;
Mikhail Naganovae9063d2023-11-07 16:43:51 -08001210 if (erasePortAfterConnectionIt != mPorts.end()) {
1211 mPorts.erase(erasePortAfterConnectionIt);
1212 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001213 } else { // !connected
1214 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1215 auto portsIt = findPort(matchDevice);
1216 if (portsIt == mPorts.end()) {
Mikhail Naganov02038012023-09-08 12:38:14 -07001217 // Since 'setConnectedState' is called for all modules, it is normal when the device
1218 // port not found in every one of them.
Mikhail Naganove93a0862023-03-15 17:06:59 -07001219 return BAD_VALUE;
Mikhail Naganov02038012023-09-08 12:38:14 -07001220 } else {
1221 ALOGD("%s: device port for device %s found in the module %s",
1222 __func__, matchDevice.toString().c_str(), mInstance.c_str());
Mikhail Naganove93a0862023-03-15 17:06:59 -07001223 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001224 resetUnusedPatchesAndPortConfigs();
Mikhail Naganovae9063d2023-11-07 16:43:51 -08001225
1226 // Disconnection of remote submix out with address "0" is a special case. We need to replace
1227 // the connected port entry with the "augmented template".
1228 const int32_t portId = portsIt->second.id;
1229 if (mRemoteSubmixOut.has_value() && matchDevice.type.type == AudioDeviceType::OUT_SUBMIX &&
1230 matchDevice.address == AudioDeviceAddress::make<AudioDeviceAddress::id>(
1231 AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS)) {
1232 mDisconnectedPortReplacement = std::make_pair(portId, *mRemoteSubmixOut);
1233 auto& port = mDisconnectedPortReplacement.second;
1234 port.ext.get<AudioPortExt::Tag::device>().device = matchDevice;
1235 port.profiles = portsIt->second.profiles;
1236 }
Mikhail Naganov66907492023-09-11 17:22:03 -07001237 // Streams are closed by AudioFlinger independently from device disconnections.
1238 // It is possible that the stream has not been closed yet.
Mikhail Naganov66907492023-09-11 17:22:03 -07001239 if (!isPortHeldByAStream(portId)) {
1240 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1241 mModule->disconnectExternalDevice(portId)));
Mikhail Naganovae9063d2023-11-07 16:43:51 -08001242 eraseConnectedPort(portId);
Mikhail Naganov66907492023-09-11 17:22:03 -07001243 } else {
1244 ALOGD("%s: since device port ID %d is used by a stream, "
1245 "external device disconnection postponed", __func__, portId);
Mikhail Naganov892f7612023-09-15 18:55:39 -07001246 mConnectedPorts[portId] = true;
Mikhail Naganov66907492023-09-11 17:22:03 -07001247 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001248 }
Mikhail Naganov289468a2023-03-29 10:06:15 -07001249 return updateRoutes();
Mikhail Naganove93a0862023-03-15 17:06:59 -07001250}
1251
1252status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
1253 TIME_CHECK();
1254 if (!mModule) return NO_INIT;
Mikhail Naganov66907492023-09-11 17:22:03 -07001255 resetUnusedPatchesAndPortConfigs();
Mikhail Naganove93a0862023-03-15 17:06:59 -07001256 ModuleDebug debug{ .simulateDeviceConnections = enabled };
1257 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
1258 // This is important to log as it affects HAL behavior.
1259 if (status == OK) {
1260 ALOGI("%s: set enabled: %d", __func__, enabled);
1261 } else {
1262 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
1263 }
1264 return status;
1265}
1266
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001267bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
1268 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1269 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1270}
1271
1272bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
1273 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1274 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1275 return p.portId == mDefaultInputPortId;
1276 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1277 return p.portId == mDefaultOutputPortId;
1278 }
1279 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1280}
1281
David Lia8675d42023-03-30 21:08:06 +08001282status_t DeviceHalAidl::createOrUpdatePortConfig(
1283 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool* created) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001284 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001285 AudioPortConfig appliedPortConfig;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001286 bool applied = false;
1287 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001288 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001289 if (!applied) {
1290 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001291 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001292 if (!applied) {
1293 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001294 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001295 return NO_INIT;
1296 }
1297 }
David Lia8675d42023-03-30 21:08:06 +08001298
1299 int32_t id = appliedPortConfig.id;
1300 if (requestedPortConfig.id != 0 && requestedPortConfig.id != id) {
1301 LOG_ALWAYS_FATAL("%s: requested port config id %d changed to %d", __func__,
1302 requestedPortConfig.id, id);
1303 }
1304
1305 auto [it, inserted] = mPortConfigs.insert_or_assign(std::move(id),
1306 std::move(appliedPortConfig));
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001307 *result = it;
David Lia8675d42023-03-30 21:08:06 +08001308 *created = inserted;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001309 return OK;
1310}
1311
Mikhail Naganovae9063d2023-11-07 16:43:51 -08001312void DeviceHalAidl::eraseConnectedPort(int32_t portId) {
1313 mPorts.erase(portId);
1314 mConnectedPorts.erase(portId);
1315 if (mDisconnectedPortReplacement.first == portId) {
1316 const auto& port = mDisconnectedPortReplacement.second;
1317 mPorts.insert(std::make_pair(port.id, port));
1318 ALOGD("%s: disconnected port replacement: %s", __func__, port.toString().c_str());
1319 mDisconnectedPortReplacement = std::pair<int32_t, AudioPort>();
1320 }
1321}
1322
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001323status_t DeviceHalAidl::filterAndRetrieveBtA2dpParameters(
1324 AudioParameter &keys, AudioParameter *result) {
1325 TIME_CHECK();
1326 if (String8 key = String8(AudioParameter::keyReconfigA2dpSupported); keys.containsKey(key)) {
1327 keys.remove(key);
David Lia7761ed2023-11-03 17:22:07 +00001328 if (mBluetoothA2dp != nullptr) {
1329 bool supports;
1330 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1331 mBluetoothA2dp->supportsOffloadReconfiguration(&supports)));
1332 result->addInt(key, supports ? 1 : 0);
1333 } else {
1334 ALOGI("%s: no IBluetoothA2dp on %s", __func__, mInstance.c_str());
1335 result->addInt(key, 0);
1336 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001337 }
1338 return OK;
1339}
1340
Mikhail Naganovccc82112023-04-27 18:14:15 -07001341status_t DeviceHalAidl::filterAndUpdateBtA2dpParameters(AudioParameter &parameters) {
1342 TIME_CHECK();
1343 std::optional<bool> a2dpEnabled;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001344 std::optional<std::vector<VendorParameter>> reconfigureOffload;
Mikhail Naganovccc82112023-04-27 18:14:15 -07001345 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1346 parameters, String8(AudioParameter::keyBtA2dpSuspended),
1347 [&a2dpEnabled](const String8& trueOrFalse) {
1348 if (trueOrFalse == AudioParameter::valueTrue) {
1349 a2dpEnabled = false; // 'suspended' == true
1350 return OK;
1351 } else if (trueOrFalse == AudioParameter::valueFalse) {
1352 a2dpEnabled = true; // 'suspended' == false
1353 return OK;
1354 }
1355 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1356 AudioParameter::keyBtA2dpSuspended, trueOrFalse.c_str());
1357 return BAD_VALUE;
1358 }));
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001359 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1360 parameters, String8(AudioParameter::keyReconfigA2dp),
1361 [&](const String8& value) -> status_t {
1362 if (mVendorExt != nullptr) {
1363 std::vector<VendorParameter> result;
1364 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
1365 mVendorExt->parseBluetoothA2dpReconfigureOffload(
1366 std::string(value.c_str()), &result)));
1367 reconfigureOffload = std::move(result);
1368 } else {
1369 reconfigureOffload = std::vector<VendorParameter>();
1370 }
1371 return OK;
1372 }));
Mikhail Naganovccc82112023-04-27 18:14:15 -07001373 if (mBluetoothA2dp != nullptr && a2dpEnabled.has_value()) {
1374 return statusTFromBinderStatus(mBluetoothA2dp->setEnabled(a2dpEnabled.value()));
1375 }
Mikhail Naganove7a26ad2023-05-25 17:36:48 -07001376 if (mBluetoothA2dp != nullptr && reconfigureOffload.has_value()) {
1377 return statusTFromBinderStatus(mBluetoothA2dp->reconfigureOffload(
1378 reconfigureOffload.value()));
1379 }
Mikhail Naganovccc82112023-04-27 18:14:15 -07001380 return OK;
1381}
1382
1383status_t DeviceHalAidl::filterAndUpdateBtHfpParameters(AudioParameter &parameters) {
1384 TIME_CHECK();
1385 IBluetooth::HfpConfig hfpConfig;
1386 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1387 parameters, String8(AudioParameter::keyBtHfpEnable),
1388 [&hfpConfig](const String8& trueOrFalse) {
1389 if (trueOrFalse == AudioParameter::valueTrue) {
1390 hfpConfig.isEnabled = Boolean{ .value = true };
1391 return OK;
1392 } else if (trueOrFalse == AudioParameter::valueFalse) {
1393 hfpConfig.isEnabled = Boolean{ .value = false };
1394 return OK;
1395 }
1396 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1397 AudioParameter::keyBtHfpEnable, trueOrFalse.c_str());
1398 return BAD_VALUE;
1399 }));
1400 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1401 parameters, String8(AudioParameter::keyBtHfpSamplingRate),
1402 [&hfpConfig](int sampleRate) {
1403 return sampleRate > 0 ?
1404 hfpConfig.sampleRate = Int{ .value = sampleRate }, OK : BAD_VALUE;
1405 }));
1406 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1407 parameters, String8(AudioParameter::keyBtHfpVolume),
1408 [&hfpConfig](int volume0to15) {
1409 if (volume0to15 >= 0 && volume0to15 <= 15) {
1410 hfpConfig.volume = Float{ .value = volume0to15 / 15.0f };
1411 return OK;
1412 }
1413 return BAD_VALUE;
1414 }));
1415 if (mBluetooth != nullptr && hfpConfig != IBluetooth::HfpConfig{}) {
1416 IBluetooth::HfpConfig newHfpConfig;
1417 return statusTFromBinderStatus(mBluetooth->setHfpConfig(hfpConfig, &newHfpConfig));
1418 }
1419 return OK;
1420}
1421
1422status_t DeviceHalAidl::filterAndUpdateBtLeParameters(AudioParameter &parameters) {
1423 TIME_CHECK();
1424 std::optional<bool> leEnabled;
1425 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1426 parameters, String8(AudioParameter::keyBtLeSuspended),
1427 [&leEnabled](const String8& trueOrFalse) {
1428 if (trueOrFalse == AudioParameter::valueTrue) {
1429 leEnabled = false; // 'suspended' == true
1430 return OK;
1431 } else if (trueOrFalse == AudioParameter::valueFalse) {
1432 leEnabled = true; // 'suspended' == false
1433 return OK;
1434 }
1435 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1436 AudioParameter::keyBtLeSuspended, trueOrFalse.c_str());
1437 return BAD_VALUE;
1438 }));
1439 if (mBluetoothLe != nullptr && leEnabled.has_value()) {
1440 return statusTFromBinderStatus(mBluetoothLe->setEnabled(leEnabled.value()));
1441 }
1442 return OK;
1443}
1444
1445status_t DeviceHalAidl::filterAndUpdateBtScoParameters(AudioParameter &parameters) {
1446 TIME_CHECK();
1447 IBluetooth::ScoConfig scoConfig;
1448 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1449 parameters, String8(AudioParameter::keyBtSco),
1450 [&scoConfig](const String8& onOrOff) {
1451 if (onOrOff == AudioParameter::valueOn) {
1452 scoConfig.isEnabled = Boolean{ .value = true };
1453 return OK;
1454 } else if (onOrOff == AudioParameter::valueOff) {
1455 scoConfig.isEnabled = Boolean{ .value = false };
1456 return OK;
1457 }
1458 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1459 AudioParameter::keyBtSco, onOrOff.c_str());
1460 return BAD_VALUE;
1461 }));
1462 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1463 parameters, String8(AudioParameter::keyBtScoHeadsetName),
1464 [&scoConfig](const String8& name) {
1465 scoConfig.debugName = name;
1466 return OK;
1467 }));
1468 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1469 parameters, String8(AudioParameter::keyBtNrec),
1470 [&scoConfig](const String8& onOrOff) {
1471 if (onOrOff == AudioParameter::valueOn) {
1472 scoConfig.isNrecEnabled = Boolean{ .value = true };
1473 return OK;
1474 } else if (onOrOff == AudioParameter::valueOff) {
1475 scoConfig.isNrecEnabled = Boolean{ .value = false };
1476 return OK;
1477 }
1478 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1479 AudioParameter::keyBtNrec, onOrOff.c_str());
1480 return BAD_VALUE;
1481 }));
1482 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1483 parameters, String8(AudioParameter::keyBtScoWb),
1484 [&scoConfig](const String8& onOrOff) {
1485 if (onOrOff == AudioParameter::valueOn) {
1486 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO_WB;
1487 return OK;
1488 } else if (onOrOff == AudioParameter::valueOff) {
1489 scoConfig.mode = IBluetooth::ScoConfig::Mode::SCO;
1490 return OK;
1491 }
1492 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1493 AudioParameter::keyBtScoWb, onOrOff.c_str());
1494 return BAD_VALUE;
1495 }));
1496 if (mBluetooth != nullptr && scoConfig != IBluetooth::ScoConfig{}) {
1497 IBluetooth::ScoConfig newScoConfig;
1498 return statusTFromBinderStatus(mBluetooth->setScoConfig(scoConfig, &newScoConfig));
1499 }
1500 return OK;
1501}
1502
Mikhail Naganove92c34b2023-05-31 14:24:48 -07001503status_t DeviceHalAidl::filterAndUpdateScreenParameters(AudioParameter &parameters) {
1504 TIME_CHECK();
1505 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1506 parameters, String8(AudioParameter::keyScreenState),
1507 [&](const String8& onOrOff) -> status_t {
1508 std::optional<bool> isTurnedOn;
1509 if (onOrOff == AudioParameter::valueOn) {
1510 isTurnedOn = true;
1511 } else if (onOrOff == AudioParameter::valueOff) {
1512 isTurnedOn = false;
1513 }
1514 if (!isTurnedOn.has_value()) {
1515 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1516 AudioParameter::keyScreenState, onOrOff.c_str());
1517 return BAD_VALUE;
1518 }
1519 return statusTFromBinderStatus(
1520 mModule->updateScreenState(isTurnedOn.value()));
1521 }));
1522 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1523 parameters, String8(AudioParameter::keyScreenRotation),
1524 [&](int rotationDegrees) -> status_t {
1525 IModule::ScreenRotation rotation;
1526 switch (rotationDegrees) {
1527 case 0: rotation = IModule::ScreenRotation::DEG_0; break;
1528 case 90: rotation = IModule::ScreenRotation::DEG_90; break;
1529 case 180: rotation = IModule::ScreenRotation::DEG_180; break;
1530 case 270: rotation = IModule::ScreenRotation::DEG_270; break;
1531 default:
1532 ALOGE("setParameters: parameter key \"%s\" has invalid value %d",
1533 AudioParameter::keyScreenRotation, rotationDegrees);
1534 return BAD_VALUE;
1535 }
1536 return statusTFromBinderStatus(mModule->updateScreenRotation(rotation));
1537 }));
1538 return OK;
1539}
1540
Mikhail Naganovb9a81312023-07-18 13:55:34 -07001541status_t DeviceHalAidl::filterAndUpdateTelephonyParameters(AudioParameter &parameters) {
1542 TIME_CHECK();
1543 using TtyMode = ITelephony::TelecomConfig::TtyMode;
1544 ITelephony::TelecomConfig telConfig;
1545 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1546 parameters, String8(AudioParameter::keyTtyMode),
1547 [&telConfig](const String8& mode) {
1548 if (mode == AudioParameter::valueTtyModeOff) {
1549 telConfig.ttyMode = TtyMode::OFF;
1550 return OK;
1551 } else if (mode == AudioParameter::valueTtyModeFull) {
1552 telConfig.ttyMode = TtyMode::FULL;
1553 return OK;
1554 } else if (mode == AudioParameter::valueTtyModeHco) {
1555 telConfig.ttyMode = TtyMode::HCO;
1556 return OK;
1557 } else if (mode == AudioParameter::valueTtyModeVco) {
1558 telConfig.ttyMode = TtyMode::VCO;
1559 return OK;
1560 }
1561 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1562 AudioParameter::keyTtyMode, mode.c_str());
1563 return BAD_VALUE;
1564 }));
1565 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
1566 parameters, String8(AudioParameter::keyHacSetting),
1567 [&telConfig](const String8& onOrOff) {
1568 if (onOrOff == AudioParameter::valueHacOn) {
1569 telConfig.isHacEnabled = Boolean{ .value = true };
1570 return OK;
1571 } else if (onOrOff == AudioParameter::valueHacOff) {
1572 telConfig.isHacEnabled = Boolean{ .value = false };
1573 return OK;
1574 }
1575 ALOGE("setParameters: parameter key \"%s\" has invalid value \"%s\"",
1576 AudioParameter::keyHacSetting, onOrOff.c_str());
1577 return BAD_VALUE;
1578 }));
1579 if (mTelephony != nullptr && telConfig != ITelephony::TelecomConfig{}) {
1580 ITelephony::TelecomConfig newTelConfig;
1581 return statusTFromBinderStatus(
1582 mTelephony->setTelecomConfig(telConfig, &newTelConfig));
1583 }
1584 return OK;
1585}
1586
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001587status_t DeviceHalAidl::findOrCreatePatch(
1588 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
1589 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
1590 requestedPatch.sourcePortConfigIds.end());
1591 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
1592 requestedPatch.sinkPortConfigIds.end());
1593 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
1594}
1595
1596status_t DeviceHalAidl::findOrCreatePatch(
1597 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
1598 AudioPatch* patch, bool* created) {
1599 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
1600 if (patchIt == mPatches.end()) {
1601 TIME_CHECK();
1602 AudioPatch requestedPatch, appliedPatch;
1603 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
1604 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
1605 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
1606 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
1607 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
1608 requestedPatch, &appliedPatch)));
1609 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
1610 *created = true;
1611 } else {
1612 *created = false;
1613 }
1614 *patch = patchIt->second;
1615 return OK;
1616}
1617
jiabin9c07faf2023-04-26 22:00:44 +00001618status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device, const AudioConfig* config,
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001619 AudioPortConfig* portConfig, bool* created) {
1620 auto portConfigIt = findPortConfig(device);
1621 if (portConfigIt == mPortConfigs.end()) {
1622 auto portsIt = findPort(device);
1623 if (portsIt == mPorts.end()) {
1624 ALOGE("%s: device port for device %s is not found in the module %s",
1625 __func__, device.toString().c_str(), mInstance.c_str());
1626 return BAD_VALUE;
1627 }
1628 AudioPortConfig requestedPortConfig;
1629 requestedPortConfig.portId = portsIt->first;
jiabin9c07faf2023-04-26 22:00:44 +00001630 if (config != nullptr) {
1631 setPortConfigFromConfig(&requestedPortConfig, *config);
1632 }
David Lia8675d42023-03-30 21:08:06 +08001633 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1634 created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001635 } else {
1636 *created = false;
1637 }
1638 *portConfig = portConfigIt->second;
1639 return OK;
1640}
1641
1642status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001643 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001644 AudioSource source, const std::set<int32_t>& destinationPortIds,
1645 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001646 // These flags get removed one by one in this order when retrying port finding.
1647 static const std::vector<AudioInputFlags> kOptionalInputFlags{
1648 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001649 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001650 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001651 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
1652 AudioIoFlags matchFlags = flags.value();
Mikhail Naganov289468a2023-03-29 10:06:15 -07001653 auto portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001654 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
1655 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
1656 if (!isBitPositionFlagSet(
1657 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
1658 ++optionalInputFlagsIt;
1659 continue;
1660 }
1661 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
1662 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
Mikhail Naganov289468a2023-03-29 10:06:15 -07001663 portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001664 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
1665 "retried with flags %s", __func__, config.toString().c_str(),
1666 flags.value().toString().c_str(), mInstance.c_str(),
1667 matchFlags.toString().c_str());
1668 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001669 if (portsIt == mPorts.end()) {
1670 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001671 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001672 mInstance.c_str());
1673 return BAD_VALUE;
1674 }
1675 AudioPortConfig requestedPortConfig;
1676 requestedPortConfig.portId = portsIt->first;
1677 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001678 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001679 if (matchFlags.getTag() == AudioIoFlags::Tag::input
1680 && source != AudioSource::SYS_RESERVED_INVALID) {
1681 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
1682 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
1683 }
David Lia8675d42023-03-30 21:08:06 +08001684 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1685 created));
Mikhail Naganov61ccb482023-09-08 17:10:16 -07001686 } else if (portConfigIt == mPortConfigs.end() && !flags.has_value()) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001687 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
1688 "and was not created as flags are not specified",
1689 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
1690 return BAD_VALUE;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001691 } else {
David Lia8675d42023-03-30 21:08:06 +08001692 AudioPortConfig requestedPortConfig = portConfigIt->second;
1693 if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
1694 AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
1695 if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
1696 source != AudioSource::SYS_RESERVED_INVALID) {
1697 mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
1698 }
1699 }
1700
1701 if (requestedPortConfig != portConfigIt->second) {
1702 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1703 created));
1704 } else {
1705 *created = false;
1706 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001707 }
1708 *portConfig = portConfigIt->second;
1709 return OK;
1710}
1711
1712status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001713 const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
1714 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001715 using Tag = AudioPortExt::Tag;
1716 if (requestedPortConfig.ext.getTag() == Tag::mix) {
1717 if (const auto& p = requestedPortConfig;
1718 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001719 !p.format.has_value()) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001720 ALOGW("%s: provided mix port config is not fully specified: %s",
1721 __func__, p.toString().c_str());
1722 return BAD_VALUE;
1723 }
1724 AudioConfig config;
1725 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001726 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
1727 AudioPortMixExtUseCase::Tag::source ?
1728 requestedPortConfig.ext.get<Tag::mix>().usecase.
1729 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001730 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001731 requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
1732 portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001733 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
1734 return findOrCreatePortConfig(
jiabin9c07faf2023-04-26 22:00:44 +00001735 requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
1736 portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001737 }
1738 ALOGW("%s: unsupported audio port config: %s",
1739 __func__, requestedPortConfig.toString().c_str());
1740 return BAD_VALUE;
1741}
1742
1743DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
1744 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
1745 return std::find_if(mPatches.begin(), mPatches.end(),
1746 [&](const auto& pair) {
1747 const auto& p = pair.second;
1748 std::set<int32_t> patchSrcs(
1749 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
1750 std::set<int32_t> patchSinks(
1751 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
1752 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
1753}
1754
1755DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001756 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1757 return mPorts.find(mDefaultInputPortId);
1758 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1759 return mPorts.find(mDefaultOutputPortId);
1760 }
Mikhail Naganov892f7612023-09-15 18:55:39 -07001761 if (device.address.getTag() != AudioDeviceAddress::id ||
1762 !device.address.get<AudioDeviceAddress::id>().empty()) {
1763 return std::find_if(mPorts.begin(), mPorts.end(),
1764 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
1765 }
1766 // For connection w/o an address, two ports can be found: the template port,
1767 // and a connected port (if exists). Make sure we return the connected port.
1768 DeviceHalAidl::Ports::iterator portIt = mPorts.end();
1769 for (auto it = mPorts.begin(); it != mPorts.end(); ++it) {
1770 if (audioDeviceMatches(device, it->second)) {
1771 if (mConnectedPorts.find(it->first) != mConnectedPorts.end()) {
1772 return it;
1773 } else {
1774 // Will return 'it' if there is no connected port.
1775 portIt = it;
1776 }
1777 }
1778 }
1779 return portIt;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001780}
1781
1782DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001783 const AudioConfig& config, const AudioIoFlags& flags,
1784 const std::set<int32_t>& destinationPortIds) {
Mikhail Naganove93a0862023-03-15 17:06:59 -07001785 auto belongsToProfile = [&config](const AudioProfile& prof) {
1786 return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
1787 (config.base.channelMask.getTag() == AudioChannelLayout::none ||
1788 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
1789 config.base.channelMask) != prof.channelMasks.end()) &&
1790 (config.base.sampleRate == 0 ||
1791 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
1792 config.base.sampleRate) != prof.sampleRates.end());
1793 };
jiabin9c07faf2023-04-26 22:00:44 +00001794 static const std::vector<AudioOutputFlags> kOptionalOutputFlags{AudioOutputFlags::BIT_PERFECT};
1795 int optionalFlags = 0;
1796 auto flagMatches = [&flags, &optionalFlags](const AudioIoFlags& portFlags) {
1797 // Ports should be able to match if the optional flags are not requested.
1798 return portFlags == flags ||
1799 (portFlags.getTag() == AudioIoFlags::Tag::output &&
1800 AudioIoFlags::make<AudioIoFlags::Tag::output>(
1801 portFlags.get<AudioIoFlags::Tag::output>() &
1802 ~optionalFlags) == flags);
1803 };
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001804 auto matcher = [&](const auto& pair) {
1805 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001806 return p.ext.getTag() == AudioPortExt::Tag::mix &&
jiabin9c07faf2023-04-26 22:00:44 +00001807 flagMatches(p.flags) &&
Mikhail Naganov289468a2023-03-29 10:06:15 -07001808 (destinationPortIds.empty() ||
1809 std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
1810 [&](const int32_t destId) { return mRoutingMatrix.count(
1811 std::make_pair(p.id, destId)) != 0; })) &&
Mikhail Naganove93a0862023-03-15 17:06:59 -07001812 (p.profiles.empty() ||
1813 std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
1814 p.profiles.end()); };
jiabin9c07faf2023-04-26 22:00:44 +00001815 auto result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1816 if (result == mPorts.end() && flags.getTag() == AudioIoFlags::Tag::output) {
1817 auto optionalOutputFlagsIt = kOptionalOutputFlags.begin();
1818 while (result == mPorts.end() && optionalOutputFlagsIt != kOptionalOutputFlags.end()) {
1819 if (isBitPositionFlagSet(
1820 flags.get<AudioIoFlags::Tag::output>(), *optionalOutputFlagsIt)) {
1821 // If the flag is set by the request, it must be matched.
1822 ++optionalOutputFlagsIt;
1823 continue;
1824 }
1825 optionalFlags |= makeBitPositionFlagMask(*optionalOutputFlagsIt++);
1826 result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1827 ALOGI("%s: port for config %s, flags %s was not found in the module %s, "
1828 "retried with excluding optional flags %#x", __func__, config.toString().c_str(),
1829 flags.toString().c_str(), mInstance.c_str(), optionalFlags);
1830 }
1831 }
1832 return result;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001833}
1834
1835DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001836 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001837 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001838}
1839
1840DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
jiabin12537fc2023-10-12 17:56:08 +00001841 const std::optional<AudioConfig>& config,
1842 const std::optional<AudioIoFlags>& flags,
1843 int32_t ioHandle) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001844 using Tag = AudioPortExt::Tag;
1845 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
1846 [&](const auto& pair) {
1847 const auto& p = pair.second;
1848 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
Mikhail Naganove592f1c2023-10-05 17:47:01 -07001849 (!p.sampleRate.has_value() || !p.channelMask.has_value() ||
1850 !p.format.has_value() || !p.flags.has_value()),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001851 "%s: stored mix port config is not fully specified: %s",
1852 __func__, p.toString().c_str());
1853 return p.ext.getTag() == Tag::mix &&
jiabin12537fc2023-10-12 17:56:08 +00001854 (!config.has_value() ||
1855 isConfigEqualToPortConfig(config.value(), p)) &&
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001856 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001857 p.ext.template get<Tag::mix>().handle == ioHandle; });
1858}
Mikhail Naganove93a0862023-03-15 17:06:59 -07001859
Mikhail Naganov66907492023-09-11 17:22:03 -07001860bool DeviceHalAidl::isPortHeldByAStream(int32_t portId) {
1861 // It is assumed that mStreams has already been cleaned up.
1862 for (const auto& streamPair : mStreams) {
1863 int32_t patchId = streamPair.second;
1864 auto patchIt = mPatches.find(patchId);
1865 if (patchIt == mPatches.end()) continue;
1866 for (int32_t id : patchIt->second.sourcePortConfigIds) {
1867 auto portConfigIt = mPortConfigs.find(id);
1868 if (portConfigIt != mPortConfigs.end() && portConfigIt->second.portId == portId) {
1869 return true;
1870 }
1871 }
1872 for (int32_t id : patchIt->second.sinkPortConfigIds) {
1873 auto portConfigIt = mPortConfigs.find(id);
1874 if (portConfigIt != mPortConfigs.end() && portConfigIt->second.portId == portId) {
1875 return true;
1876 }
1877 }
1878 }
1879 return false;
1880}
1881
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001882void DeviceHalAidl::resetPatch(int32_t patchId) {
1883 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1884 mPatches.erase(it);
1885 TIME_CHECK();
1886 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1887 ALOGE("%s: error while resetting patch %d: %s",
1888 __func__, patchId, status.getDescription().c_str());
1889 }
1890 return;
1891 }
1892 ALOGE("%s: patch id %d not found", __func__, patchId);
1893}
1894
1895void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1896 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1897 mPortConfigs.erase(it);
1898 TIME_CHECK();
1899 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1900 !status.isOk()) {
1901 ALOGE("%s: error while resetting port config %d: %s",
1902 __func__, portConfigId, status.getDescription().c_str());
1903 }
1904 return;
1905 }
1906 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1907}
1908
Mikhail Naganove93a0862023-03-15 17:06:59 -07001909void DeviceHalAidl::resetUnusedPatches() {
1910 // Since patches can be created independently of streams via 'createAudioPatch',
1911 // here we only clean up patches for released streams.
1912 for (auto it = mStreams.begin(); it != mStreams.end(); ) {
1913 if (auto streamSp = it->first.promote(); streamSp) {
1914 ++it;
1915 } else {
1916 resetPatch(it->second);
1917 it = mStreams.erase(it);
1918 }
1919 }
1920}
1921
1922void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
1923 resetUnusedPatches();
1924 resetUnusedPortConfigs();
1925}
1926
1927void DeviceHalAidl::resetUnusedPortConfigs() {
1928 // The assumption is that port configs are used to create patches
1929 // (or to open streams, but that involves creation of patches, too). Thus,
1930 // orphaned port configs can and should be reset.
Mikhail Naganov66907492023-09-11 17:22:03 -07001931 std::map<int32_t, int32_t /*portID*/> portConfigIds;
Mikhail Naganove93a0862023-03-15 17:06:59 -07001932 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
1933 std::inserter(portConfigIds, portConfigIds.end()),
Mikhail Naganov66907492023-09-11 17:22:03 -07001934 [](const auto& pcPair) { return std::make_pair(pcPair.first, pcPair.second.portId); });
Mikhail Naganove93a0862023-03-15 17:06:59 -07001935 for (const auto& p : mPatches) {
1936 for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
1937 for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
1938 }
jiabin9c07faf2023-04-26 22:00:44 +00001939 for (int32_t id : mInitialPortConfigIds) {
1940 portConfigIds.erase(id);
1941 }
Mikhail Naganov66907492023-09-11 17:22:03 -07001942 std::set<int32_t> retryDeviceDisconnection;
1943 for (const auto& portConfigAndIdPair : portConfigIds) {
1944 resetPortConfig(portConfigAndIdPair.first);
Mikhail Naganov892f7612023-09-15 18:55:39 -07001945 if (const auto it = mConnectedPorts.find(portConfigAndIdPair.second);
1946 it != mConnectedPorts.end() && it->second) {
Mikhail Naganov66907492023-09-11 17:22:03 -07001947 retryDeviceDisconnection.insert(portConfigAndIdPair.second);
1948 }
1949 }
1950 for (int32_t portId : retryDeviceDisconnection) {
1951 if (!isPortHeldByAStream(portId)) {
1952 TIME_CHECK();
1953 if (auto status = mModule->disconnectExternalDevice(portId); status.isOk()) {
Mikhail Naganovae9063d2023-11-07 16:43:51 -08001954 eraseConnectedPort(portId);
Mikhail Naganov66907492023-09-11 17:22:03 -07001955 ALOGD("%s: executed postponed external device disconnection for port ID %d",
1956 __func__, portId);
1957 }
1958 }
1959 }
1960 if (!retryDeviceDisconnection.empty()) {
1961 updateRoutes();
1962 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001963}
1964
Mikhail Naganov289468a2023-03-29 10:06:15 -07001965status_t DeviceHalAidl::updateRoutes() {
1966 TIME_CHECK();
Mikhail Naganov289468a2023-03-29 10:06:15 -07001967 RETURN_STATUS_IF_ERROR(
Mikhail Naganovf83b9742023-04-24 13:06:04 -07001968 statusTFromBinderStatus(mModule->getAudioRoutes(&mRoutes)));
1969 ALOGW_IF(mRoutes.empty(), "%s: module %s returned an empty list of audio routes",
Mikhail Naganov289468a2023-03-29 10:06:15 -07001970 __func__, mInstance.c_str());
Mikhail Naganovae9063d2023-11-07 16:43:51 -08001971 if (mRemoteSubmixIn.has_value()) {
1972 // Remove mentions of the template remote submix input from routes.
1973 int32_t rSubmixInId = mRemoteSubmixIn->id;
1974 // Remove mentions of the template remote submix out only if it is not in mPorts
1975 // (that means there is a connected port in mPorts).
1976 int32_t rSubmixOutId = mPorts.find(mRemoteSubmixOut->id) == mPorts.end() ?
1977 mRemoteSubmixOut->id : -1;
1978 for (auto it = mRoutes.begin(); it != mRoutes.end();) {
1979 auto& route = *it;
1980 if (route.sinkPortId == rSubmixOutId) {
1981 it = mRoutes.erase(it);
1982 continue;
1983 }
1984 if (auto sourceIt = std::find(route.sourcePortIds.begin(), route.sourcePortIds.end(),
1985 rSubmixInId); sourceIt != route.sourcePortIds.end()) {
1986 route.sourcePortIds.erase(sourceIt);
1987 if (route.sourcePortIds.empty()) {
1988 it = mRoutes.erase(it);
1989 continue;
1990 }
1991 }
1992 ++it;
1993 }
1994 }
Mikhail Naganov289468a2023-03-29 10:06:15 -07001995 mRoutingMatrix.clear();
Mikhail Naganovf83b9742023-04-24 13:06:04 -07001996 for (const auto& r : mRoutes) {
Mikhail Naganov289468a2023-03-29 10:06:15 -07001997 for (auto portId : r.sourcePortIds) {
1998 mRoutingMatrix.emplace(r.sinkPortId, portId);
1999 mRoutingMatrix.emplace(portId, r.sinkPortId);
2000 }
2001 }
2002 return OK;
2003}
2004
jiabin12537fc2023-10-12 17:56:08 +00002005status_t DeviceHalAidl::getAudioPort(int32_t portId, AudioPort* port) {
2006 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
2007 TIME_CHECK();
2008 if (!mModule) {
2009 return NO_INIT;
2010 }
2011 const status_t status = statusTFromBinderStatus(mModule->getAudioPort(portId, port));
2012 if (status == OK) {
2013 auto portIt = mPorts.find(portId);
2014 if (portIt != mPorts.end()) {
2015 portIt->second = *port;
2016 } else {
2017 ALOGW("%s, port(%d) returned successfully from the HAL but not it is not cached",
2018 __func__, portId);
2019 }
2020 }
2021 return status;
2022}
2023
Mikhail Naganovdfd594e2023-02-08 16:59:41 -08002024void DeviceHalAidl::clearCallbacks(void* cookie) {
2025 std::lock_guard l(mLock);
2026 mCallbacks.erase(cookie);
2027}
2028
2029sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
2030 return getCallbackImpl(cookie, &Callbacks::out);
2031}
2032
2033void DeviceHalAidl::setStreamOutCallback(
2034 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
2035 setCallbackImpl(cookie, &Callbacks::out, cb);
2036}
2037
2038sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
2039 void* cookie) {
2040 return getCallbackImpl(cookie, &Callbacks::event);
2041}
2042
2043void DeviceHalAidl::setStreamOutEventCallback(
2044 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
2045 setCallbackImpl(cookie, &Callbacks::event, cb);
2046}
2047
2048sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
2049 void* cookie) {
2050 return getCallbackImpl(cookie, &Callbacks::latency);
2051}
2052
2053void DeviceHalAidl::setStreamOutLatencyModeCallback(
2054 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
2055 setCallbackImpl(cookie, &Callbacks::latency, cb);
2056}
2057
2058template<class C>
2059sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
2060 std::lock_guard l(mLock);
2061 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
2062 return ((it->second).*field).promote();
2063 }
2064 return nullptr;
2065}
2066template<class C>
2067void DeviceHalAidl::setCallbackImpl(
2068 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
2069 std::lock_guard l(mLock);
2070 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
2071 (it->second).*field = cb;
2072 }
2073}
2074
Mikhail Naganov31d46652023-01-10 18:29:25 +00002075} // namespace android