blob: aafe6e0f019c15318cce40fd4bd2138528d8b9ac [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"
Vlad Popa03bd5bc2023-01-17 16:16:51 +010018// #define LOG_NDEBUG 0
Shunkai Yao51202502022-12-12 06:11:46 +000019
Mikhail Naganovf56ce782023-01-25 11:29:11 -080020#include <algorithm>
21#include <forward_list>
22
Mikhail Naganovb0c55252023-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>
David Li9cf5e622023-03-21 00:51:10 +080026#include <android/binder_enums.h>
27#include <binder/Enums.h>
Mikhail Naganovfab697c2023-01-11 19:33:13 +000028#include <error/expected_utils.h>
29#include <media/AidlConversionCppNdk.h>
30#include <media/AidlConversionUtil.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000031#include <mediautils/TimeCheck.h>
Mikhail Naganov8bd806e2023-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"
36#include "StreamHalAidl.h"
37
Mikhail Naganovfab697c2023-01-11 19:33:13 +000038using aidl::android::aidl_utils::statusTFromBinderStatus;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -070039using aidl::android::media::audio::common::AudioChannelLayout;
Mikhail Naganovf56ce782023-01-25 11:29:11 -080040using aidl::android::media::audio::common::AudioConfig;
41using aidl::android::media::audio::common::AudioDevice;
David Li9cf5e622023-03-21 00:51:10 +080042using aidl::android::media::audio::common::AudioDeviceAddress;
Mikhail Naganov8bd806e2023-01-30 12:33:18 -080043using aidl::android::media::audio::common::AudioDeviceType;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -070044using aidl::android::media::audio::common::AudioFormatType;
Mikhail Naganov8bd806e2023-01-30 12:33:18 -080045using aidl::android::media::audio::common::AudioInputFlags;
Mikhail Naganovf56ce782023-01-25 11:29:11 -080046using aidl::android::media::audio::common::AudioIoFlags;
Mikhail Naganovb0c55252023-02-08 16:59:41 -080047using aidl::android::media::audio::common::AudioLatencyMode;
David Li9cf5e622023-03-21 00:51:10 +080048using aidl::android::media::audio::common::AudioMMapPolicy;
49using aidl::android::media::audio::common::AudioMMapPolicyInfo;
50using aidl::android::media::audio::common::AudioMMapPolicyType;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000051using aidl::android::media::audio::common::AudioMode;
Mikhail Naganovf56ce782023-01-25 11:29:11 -080052using aidl::android::media::audio::common::AudioOutputFlags;
53using aidl::android::media::audio::common::AudioPort;
54using aidl::android::media::audio::common::AudioPortConfig;
Mikhail Naganov8bd806e2023-01-30 12:33:18 -080055using aidl::android::media::audio::common::AudioPortDeviceExt;
David Li9cf5e622023-03-21 00:51:10 +080056using aidl::android::media::audio::common::AudioPortExt;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -080057using aidl::android::media::audio::common::AudioPortMixExt;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -080058using aidl::android::media::audio::common::AudioPortMixExtUseCase;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -070059using aidl::android::media::audio::common::AudioProfile;
Mikhail Naganovf56ce782023-01-25 11:29:11 -080060using aidl::android::media::audio::common::AudioSource;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000061using aidl::android::media::audio::common::Float;
David Li9cf5e622023-03-21 00:51:10 +080062using aidl::android::media::audio::common::Int;
63using aidl::android::media::audio::common::MicrophoneDynamicInfo;
64using aidl::android::media::audio::common::MicrophoneInfo;
Mikhail Naganov6352e822023-03-09 18:22:36 -080065using aidl::android::hardware::audio::common::getFrameSizeInBytes;
66using aidl::android::hardware::audio::common::isBitPositionFlagSet;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -070067using aidl::android::hardware::audio::common::isDefaultAudioFormat;
Mikhail Naganov6352e822023-03-09 18:22:36 -080068using aidl::android::hardware::audio::common::makeBitPositionFlagMask;
Mikhail Naganovf56ce782023-01-25 11:29:11 -080069using aidl::android::hardware::audio::common::RecordTrackMetadata;
70using aidl::android::hardware::audio::core::AudioPatch;
Mikhail Naganovecfafb72023-03-29 10:06:15 -070071using aidl::android::hardware::audio::core::AudioRoute;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000072using aidl::android::hardware::audio::core::IModule;
73using aidl::android::hardware::audio::core::ITelephony;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -070074using aidl::android::hardware::audio::core::ModuleDebug;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000075using aidl::android::hardware::audio::core::StreamDescriptor;
Mikhail Naganov31d46652023-01-10 18:29:25 +000076
77namespace android {
78
Mikhail Naganovf56ce782023-01-25 11:29:11 -080079namespace {
80
81bool isConfigEqualToPortConfig(const AudioConfig& config, const AudioPortConfig& portConfig) {
82 return portConfig.sampleRate.value().value == config.base.sampleRate &&
83 portConfig.channelMask.value() == config.base.channelMask &&
84 portConfig.format.value() == config.base.format;
85}
86
87void setConfigFromPortConfig(AudioConfig* config, const AudioPortConfig& portConfig) {
88 config->base.sampleRate = portConfig.sampleRate.value().value;
89 config->base.channelMask = portConfig.channelMask.value();
90 config->base.format = portConfig.format.value();
91}
92
93void setPortConfigFromConfig(AudioPortConfig* portConfig, const AudioConfig& config) {
94 portConfig->sampleRate = Int{ .value = config.base.sampleRate };
95 portConfig->channelMask = config.base.channelMask;
96 portConfig->format = config.base.format;
97}
98
David Li9cf5e622023-03-21 00:51:10 +080099template<typename OutEnum, typename OutEnumRange, typename InEnum>
100ConversionResult<OutEnum> convertEnum(const OutEnumRange& range, InEnum e) {
101 using InIntType = std::underlying_type_t<InEnum>;
102 static_assert(std::is_same_v<InIntType, std::underlying_type_t<OutEnum>>);
103
104 InIntType inEnumIndex = static_cast<InIntType>(e);
105 OutEnum outEnum = static_cast<OutEnum>(inEnumIndex);
106 if (std::find(range.begin(), range.end(), outEnum) == range.end()) {
107 return ::android::base::unexpected(BAD_VALUE);
108 }
109 return outEnum;
110}
111
112template<typename NdkEnum, typename CppEnum>
113ConversionResult<NdkEnum> cpp2ndk_Enum(CppEnum e) {
114 return convertEnum<NdkEnum>(::ndk::enum_range<NdkEnum>(), e);
115}
116
117template<typename CppEnum, typename NdkEnum>
118ConversionResult<CppEnum> ndk2cpp_Enum(NdkEnum e) {
119 return convertEnum<CppEnum>(::android::enum_range<CppEnum>(), e);
120}
121
122ConversionResult<android::media::audio::common::AudioDeviceAddress>
123ndk2cpp_AudioDeviceAddress(const AudioDeviceAddress& ndk) {
124 using CppTag = android::media::audio::common::AudioDeviceAddress::Tag;
125 using NdkTag = AudioDeviceAddress::Tag;
126
127 CppTag cppTag = VALUE_OR_RETURN(ndk2cpp_Enum<CppTag>(ndk.getTag()));
128
129 switch (cppTag) {
130 case CppTag::id:
131 return android::media::audio::common::AudioDeviceAddress::make<CppTag::id>(
132 ndk.get<NdkTag::id>());
133 case CppTag::mac:
134 return android::media::audio::common::AudioDeviceAddress::make<CppTag::mac>(
135 ndk.get<NdkTag::mac>());
136 case CppTag::ipv4:
137 return android::media::audio::common::AudioDeviceAddress::make<CppTag::ipv4>(
138 ndk.get<NdkTag::ipv4>());
139 case CppTag::ipv6:
140 return android::media::audio::common::AudioDeviceAddress::make<CppTag::ipv6>(
141 ndk.get<NdkTag::ipv6>());
142 case CppTag::alsa:
143 return android::media::audio::common::AudioDeviceAddress::make<CppTag::alsa>(
144 ndk.get<NdkTag::alsa>());
145 }
146
147 return ::android::base::unexpected(BAD_VALUE);
148}
149
150ConversionResult<media::audio::common::AudioDevice> ndk2cpp_AudioDevice(const AudioDevice& ndk) {
151 media::audio::common::AudioDevice cpp;
152 cpp.type.type = VALUE_OR_RETURN(
153 ndk2cpp_Enum<media::audio::common::AudioDeviceType>(ndk.type.type));
154 cpp.type.connection = ndk.type.connection;
155 cpp.address = VALUE_OR_RETURN(ndk2cpp_AudioDeviceAddress(ndk.address));
156 return cpp;
157}
158
159ConversionResult<media::audio::common::AudioMMapPolicyInfo>
160ndk2cpp_AudioMMapPolicyInfo(const AudioMMapPolicyInfo& ndk) {
161 media::audio::common::AudioMMapPolicyInfo cpp;
162 cpp.device = VALUE_OR_RETURN(ndk2cpp_AudioDevice(ndk.device));
163 cpp.mmapPolicy = VALUE_OR_RETURN(
164 ndk2cpp_Enum<media::audio::common::AudioMMapPolicy>(ndk.mmapPolicy));
165 return cpp;
166}
167
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800168} // namespace
169
Mikhail Naganov31d46652023-01-10 18:29:25 +0000170status_t DeviceHalAidl::getSupportedDevices(uint32_t*) {
171 // Obsolete.
172 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +0000173}
174
175status_t DeviceHalAidl::initCheck() {
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800176 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000177 if (mModule == nullptr) return NO_INIT;
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800178 std::vector<AudioPort> ports;
179 RETURN_STATUS_IF_ERROR(
180 statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
181 ALOGW_IF(ports.empty(), "%s: module %s returned an empty list of audio ports",
182 __func__, mInstance.c_str());
183 std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()),
184 [](const auto& p) { return std::make_pair(p.id, p); });
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800185 mDefaultInputPortId = mDefaultOutputPortId = -1;
186 const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
187 for (const auto& pair : mPorts) {
188 const auto& p = pair.second;
189 if (p.ext.getTag() == AudioPortExt::Tag::device &&
190 (p.ext.get<AudioPortExt::Tag::device>().flags & defaultDeviceFlag) != 0) {
191 if (p.flags.getTag() == AudioIoFlags::Tag::input) {
192 mDefaultInputPortId = p.id;
193 } else if (p.flags.getTag() == AudioIoFlags::Tag::output) {
194 mDefaultOutputPortId = p.id;
195 }
196 }
197 }
198 ALOGI("%s: module %s default port ids: input %d, output %d",
199 __func__, mInstance.c_str(), mDefaultInputPortId, mDefaultOutputPortId);
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700200 RETURN_STATUS_IF_ERROR(updateRoutes());
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800201 std::vector<AudioPortConfig> portConfigs;
202 RETURN_STATUS_IF_ERROR(
203 statusTFromBinderStatus(mModule->getAudioPortConfigs(&portConfigs))); // OK if empty
204 std::transform(portConfigs.begin(), portConfigs.end(),
205 std::inserter(mPortConfigs, mPortConfigs.end()),
206 [](const auto& p) { return std::make_pair(p.id, p); });
207 std::vector<AudioPatch> patches;
208 RETURN_STATUS_IF_ERROR(
209 statusTFromBinderStatus(mModule->getAudioPatches(&patches))); // OK if empty
210 std::transform(patches.begin(), patches.end(),
211 std::inserter(mPatches, mPatches.end()),
212 [](const auto& p) { return std::make_pair(p.id, p); });
Shunkai Yao51202502022-12-12 06:11:46 +0000213 return OK;
214}
215
216status_t DeviceHalAidl::setVoiceVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000217 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000218 if (!mModule) return NO_INIT;
219 std::shared_ptr<ITelephony> telephony;
220 if (ndk::ScopedAStatus status = mModule->getTelephony(&telephony);
221 status.isOk() && telephony != nullptr) {
222 ITelephony::TelecomConfig inConfig{ .voiceVolume = Float{volume} }, outConfig;
223 RETURN_STATUS_IF_ERROR(
224 statusTFromBinderStatus(telephony->setTelecomConfig(inConfig, &outConfig)));
225 ALOGW_IF(outConfig.voiceVolume.has_value() && volume != outConfig.voiceVolume.value().value,
226 "%s: the resulting voice volume %f is not the same as requested %f",
227 __func__, outConfig.voiceVolume.value().value, volume);
228 }
229 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +0000230}
231
232status_t DeviceHalAidl::setMasterVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000233 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000234 if (!mModule) return NO_INIT;
235 return statusTFromBinderStatus(mModule->setMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000236}
237
238status_t DeviceHalAidl::getMasterVolume(float *volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000239 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000240 if (!mModule) return NO_INIT;
241 return statusTFromBinderStatus(mModule->getMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000242}
243
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000244status_t DeviceHalAidl::setMode(audio_mode_t mode) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000245 TIME_CHECK();
246 if (!mModule) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000247 AudioMode audioMode = VALUE_OR_FATAL(::aidl::android::legacy2aidl_audio_mode_t_AudioMode(mode));
248 std::shared_ptr<ITelephony> telephony;
249 if (ndk::ScopedAStatus status = mModule->getTelephony(&telephony);
250 status.isOk() && telephony != nullptr) {
251 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(telephony->switchAudioMode(audioMode)));
252 }
253 return statusTFromBinderStatus(mModule->updateAudioMode(audioMode));
Shunkai Yao51202502022-12-12 06:11:46 +0000254}
255
256status_t DeviceHalAidl::setMicMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000257 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000258 if (!mModule) return NO_INIT;
259 return statusTFromBinderStatus(mModule->setMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000260}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000261
Shunkai Yao51202502022-12-12 06:11:46 +0000262status_t DeviceHalAidl::getMicMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000263 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000264 if (!mModule) return NO_INIT;
265 return statusTFromBinderStatus(mModule->getMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000266}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000267
Shunkai Yao51202502022-12-12 06:11:46 +0000268status_t DeviceHalAidl::setMasterMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000269 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000270 if (!mModule) return NO_INIT;
271 return statusTFromBinderStatus(mModule->setMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000272}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000273
Shunkai Yao51202502022-12-12 06:11:46 +0000274status_t DeviceHalAidl::getMasterMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000275 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000276 if (!mModule) return NO_INIT;
277 return statusTFromBinderStatus(mModule->getMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000278}
279
Mikhail Naganov31d46652023-01-10 18:29:25 +0000280status_t DeviceHalAidl::setParameters(const String8& kvPairs __unused) {
281 TIME_CHECK();
282 if (!mModule) return NO_INIT;
283 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000284 return OK;
285}
286
Mikhail Naganov31d46652023-01-10 18:29:25 +0000287status_t DeviceHalAidl::getParameters(const String8& keys __unused, String8 *values) {
288 TIME_CHECK();
289 values->clear();
290 if (!mModule) return NO_INIT;
291 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000292 return OK;
293}
294
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800295namespace {
296
297class Cleanup {
298 public:
299 typedef void (DeviceHalAidl::*Cleaner)(int32_t);
300
301 Cleanup(DeviceHalAidl* device, Cleaner cleaner, int32_t id) :
302 mDevice(device), mCleaner(cleaner), mId(id) {}
303 ~Cleanup() { clean(); }
304 void clean() {
305 if (mDevice != nullptr) (mDevice->*mCleaner)(mId);
306 disarm();
307 }
308 void disarm() { mDevice = nullptr; }
309
310 private:
311 DeviceHalAidl* mDevice;
312 const Cleaner mCleaner;
313 const int32_t mId;
314};
315
316} // namespace
317
318// Since the order of container elements destruction is unspecified,
319// ensure that cleanups are performed from the most recent one and upwards.
320// This is the same as if there were individual Cleanup instances on the stack,
321// however the bonus is that we can disarm all of them with just one statement.
322class DeviceHalAidl::Cleanups : public std::forward_list<Cleanup> {
323 public:
324 ~Cleanups() { for (auto& c : *this) c.clean(); }
325 void disarmAll() { for (auto& c : *this) c.disarm(); }
326};
327
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800328status_t DeviceHalAidl::getInputBufferSize(const struct audio_config* config, size_t* size) {
329 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
330 if (size == nullptr) return BAD_VALUE;
331 TIME_CHECK();
332 if (!mModule) return NO_INIT;
333 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
334 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
335 AudioDevice aidlDevice;
336 aidlDevice.type.type = AudioDeviceType::IN_DEFAULT;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800337 AudioSource aidlSource = AudioSource::DEFAULT;
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800338 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
339 AudioPortConfig mixPortConfig;
340 Cleanups cleanups;
341 audio_config writableConfig = *config;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700342 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800343 RETURN_STATUS_IF_ERROR(prepareToOpenStream(0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700344 &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800345 *size = aidlConfig.frameCount *
346 getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
347 // Do not disarm cleanups to release temporary port configs.
348 return OK;
349}
350
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800351status_t DeviceHalAidl::prepareToOpenStream(
352 int32_t aidlHandle, const AudioDevice& aidlDevice, const AudioIoFlags& aidlFlags,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800353 AudioSource aidlSource, struct audio_config* config,
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800354 Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700355 AudioPatch* aidlPatch) {
356 ALOGD("%p %s::%s: handle %d, device %s, flags %s, source %s, config %s, mix port config %s",
357 this, getClassName().c_str(), __func__, aidlHandle, aidlDevice.toString().c_str(),
358 aidlFlags.toString().c_str(), toString(aidlSource).c_str(),
359 aidlConfig->toString().c_str(), mixPortConfig->toString().c_str());
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800360 const bool isInput = aidlFlags.getTag() == AudioIoFlags::Tag::input;
361 // Find / create AudioPortConfigs for the device port and the mix port,
362 // then find / create a patch between them, and open a stream on the mix port.
363 AudioPortConfig devicePortConfig;
364 bool created = false;
365 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, &devicePortConfig, &created));
366 if (created) {
367 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
368 }
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800369 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*aidlConfig, aidlFlags, aidlHandle, aidlSource,
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700370 std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800371 if (created) {
372 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
373 }
374 setConfigFromPortConfig(aidlConfig, *mixPortConfig);
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800375 if (isInput) {
376 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700377 {devicePortConfig.id}, {mixPortConfig->id}, aidlPatch, &created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800378 } else {
379 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700380 {mixPortConfig->id}, {devicePortConfig.id}, aidlPatch, &created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800381 }
382 if (created) {
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700383 cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, aidlPatch->id);
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800384 }
385 if (aidlConfig->frameCount <= 0) {
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700386 aidlConfig->frameCount = aidlPatch->minimumStreamBufferSizeFrames;
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800387 }
388 *config = VALUE_OR_RETURN_STATUS(
389 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(*aidlConfig, isInput));
390 return OK;
391}
392
Mikhail Naganovb0c55252023-02-08 16:59:41 -0800393namespace {
394
395class StreamCallbackBase {
396 protected:
397 explicit StreamCallbackBase(const sp<CallbackBroker>& broker) : mBroker(broker) {}
398 public:
399 void* getCookie() const { return mCookie; }
400 void setCookie(void* cookie) { mCookie = cookie; }
401 sp<CallbackBroker> getBroker() const {
402 if (void* cookie = mCookie; cookie != nullptr) return mBroker.promote();
403 return nullptr;
404 }
405 private:
406 const wp<CallbackBroker> mBroker;
407 std::atomic<void*> mCookie;
408};
409
410template<class C>
411class StreamCallbackBaseHelper {
412 protected:
413 explicit StreamCallbackBaseHelper(const StreamCallbackBase& base) : mBase(base) {}
414 sp<C> getCb(const sp<CallbackBroker>& broker, void* cookie);
415 using CbRef = const sp<C>&;
416 ndk::ScopedAStatus runCb(const std::function<void(CbRef cb)>& f) {
417 if (auto cb = getCb(mBase.getBroker(), mBase.getCookie()); cb != nullptr) f(cb);
418 return ndk::ScopedAStatus::ok();
419 }
420 private:
421 const StreamCallbackBase& mBase;
422};
423
424template<>
425sp<StreamOutHalInterfaceCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>::getCb(
426 const sp<CallbackBroker>& broker, void* cookie) {
427 if (broker != nullptr) return broker->getStreamOutCallback(cookie);
428 return nullptr;
429}
430
431template<>
432sp<StreamOutHalInterfaceEventCallback>
433StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::getCb(
434 const sp<CallbackBroker>& broker, void* cookie) {
435 if (broker != nullptr) return broker->getStreamOutEventCallback(cookie);
436 return nullptr;
437}
438
439template<>
440sp<StreamOutHalInterfaceLatencyModeCallback>
441StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::getCb(
442 const sp<CallbackBroker>& broker, void* cookie) {
443 if (broker != nullptr) return broker->getStreamOutLatencyModeCallback(cookie);
444 return nullptr;
445}
446
447/*
448Note on the callback ownership.
449
450In the Binder ownership model, the server implementation is kept alive
451as long as there is any client (proxy object) alive. This is done by
452incrementing the refcount of the server-side object by the Binder framework.
453When it detects that the last client is gone, it decrements the refcount back.
454
455Thus, it is not needed to keep any references to StreamCallback on our
456side (after we have sent an instance to the client), because we are
457the server-side. The callback object will be kept alive as long as the HAL server
458holds a strong ref to IStreamCallback proxy.
459*/
460
461class OutputStreamCallbackAidl : public StreamCallbackBase,
462 public StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>,
463 public ::aidl::android::hardware::audio::core::BnStreamCallback {
464 public:
465 explicit OutputStreamCallbackAidl(const sp<CallbackBroker>& broker)
466 : StreamCallbackBase(broker),
467 StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>(
468 *static_cast<StreamCallbackBase*>(this)) {}
469 ndk::ScopedAStatus onTransferReady() override {
470 return runCb([](CbRef cb) { cb->onWriteReady(); });
471 }
472 ndk::ScopedAStatus onError() override {
473 return runCb([](CbRef cb) { cb->onError(); });
474 }
475 ndk::ScopedAStatus onDrainReady() override {
476 return runCb([](CbRef cb) { cb->onDrainReady(); });
477 }
478};
479
480class OutputStreamEventCallbackAidl :
481 public StreamCallbackBase,
482 public StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>,
483 public StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>,
484 public ::aidl::android::hardware::audio::core::BnStreamOutEventCallback {
485 public:
486 explicit OutputStreamEventCallbackAidl(const sp<CallbackBroker>& broker)
487 : StreamCallbackBase(broker),
488 StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>(
489 *static_cast<StreamCallbackBase*>(this)),
490 StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>(
491 *static_cast<StreamCallbackBase*>(this)) {}
492 ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& in_audioMetadata) override {
493 std::basic_string<uint8_t> halMetadata(in_audioMetadata.begin(), in_audioMetadata.end());
494 return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb(
495 [&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); });
496 }
497 ndk::ScopedAStatus onRecommendedLatencyModeChanged(
498 const std::vector<AudioLatencyMode>& in_modes) override {
499 auto halModes = VALUE_OR_FATAL(
500 ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
501 in_modes,
502 ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
503 return StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::runCb(
504 [&halModes](auto cb) { cb->onRecommendedLatencyModeChanged(halModes); });
505 }
506};
507
508} // namespace
509
Mikhail Naganov31d46652023-01-10 18:29:25 +0000510status_t DeviceHalAidl::openOutputStream(
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800511 audio_io_handle_t handle, audio_devices_t devices,
512 audio_output_flags_t flags, struct audio_config* config,
513 const char* address,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000514 sp<StreamOutHalInterface>* outStream) {
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800515 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000516 if (!outStream || !config) {
517 return BAD_VALUE;
518 }
519 TIME_CHECK();
520 if (!mModule) return NO_INIT;
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800521 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
522 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
523 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
524 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, false /*isInput*/));
525 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
526 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
527 int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
528 ::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
529 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
530 AudioPortConfig mixPortConfig;
531 Cleanups cleanups;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700532 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800533 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
534 AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700535 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800536 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
537 args.portConfigId = mixPortConfig.id;
Mikhail Naganovb0c55252023-02-08 16:59:41 -0800538 const bool isOffload = isBitPositionFlagSet(
539 aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD);
540 std::shared_ptr<OutputStreamCallbackAidl> streamCb;
541 if (isOffload) {
542 streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
543 }
544 auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
545 if (isOffload) {
546 args.offloadInfo = aidlConfig.offloadInfo;
547 args.callback = streamCb;
548 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800549 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovb0c55252023-02-08 16:59:41 -0800550 args.eventCallback = eventCb;
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800551 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
552 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800553 StreamContextAidl context(ret.desc, isOffload);
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800554 if (!context.isValid()) {
555 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
556 __func__, ret.desc.toString().c_str());
557 return NO_INIT;
558 }
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700559 *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganovb0c55252023-02-08 16:59:41 -0800560 std::move(ret.stream), this /*callbackBroker*/);
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700561 mStreams.insert(std::pair(*outStream, aidlPatch.id));
Mikhail Naganovb0c55252023-02-08 16:59:41 -0800562 void* cbCookie = (*outStream).get();
563 {
564 std::lock_guard l(mLock);
565 mCallbacks.emplace(cbCookie, Callbacks{});
566 }
567 if (streamCb) streamCb->setCookie(cbCookie);
568 eventCb->setCookie(cbCookie);
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800569 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000570 return OK;
571}
572
Mikhail Naganov31d46652023-01-10 18:29:25 +0000573status_t DeviceHalAidl::openInputStream(
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800574 audio_io_handle_t handle, audio_devices_t devices,
575 struct audio_config* config, audio_input_flags_t flags,
576 const char* address, audio_source_t source,
577 audio_devices_t outputDevice, const char* outputDeviceAddress,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000578 sp<StreamInHalInterface>* inStream) {
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800579 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000580 if (!inStream || !config) {
581 return BAD_VALUE;
582 }
583 TIME_CHECK();
584 if (!mModule) return NO_INIT;
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800585 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
586 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
587 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
588 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
589 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
590 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
591 int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
592 ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
593 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
594 AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
595 ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
596 AudioPortConfig mixPortConfig;
597 Cleanups cleanups;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700598 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800599 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700600 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800601 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
602 args.portConfigId = mixPortConfig.id;
603 RecordTrackMetadata aidlTrackMetadata{
604 .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
605 if (outputDevice != AUDIO_DEVICE_NONE) {
606 aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
607 ::aidl::android::legacy2aidl_audio_device_AudioDevice(
608 outputDevice, outputDeviceAddress));
609 }
610 args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
611 args.bufferSizeFrames = aidlConfig.frameCount;
612 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
613 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800614 StreamContextAidl context(ret.desc, false /*isAsynchronous*/);
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800615 if (!context.isValid()) {
616 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
617 __func__, ret.desc.toString().c_str());
618 return NO_INIT;
619 }
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700620 *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800621 std::move(ret.stream), this /*micInfoProvider*/);
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700622 mStreams.insert(std::pair(*inStream, aidlPatch.id));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800623 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000624 return OK;
625}
626
627status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
628 *supportsPatches = true;
629 return OK;
630}
631
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800632status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
633 const struct audio_port_config* sources,
634 unsigned int num_sinks,
635 const struct audio_port_config* sinks,
636 audio_patch_handle_t* patch) {
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800637 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000638 TIME_CHECK();
639 if (!mModule) return NO_INIT;
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800640 if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
641 sources == nullptr || sinks == nullptr || patch == nullptr) {
642 return BAD_VALUE;
643 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800644 // When the patch handle (*patch) is AUDIO_PATCH_HANDLE_NONE, it means
645 // the framework wants to create a new patch. The handle has to be generated
646 // by the HAL. Since handles generated this way can only be unique within
647 // a HAL module, the framework generates a globally unique handle, and maps
648 // it on the <HAL module, patch handle> pair.
649 // When the patch handle is set, it meant the framework intends to update
650 // an existing patch.
651 //
652 // This behavior corresponds to HAL module behavior, with the only difference
653 // that the HAL module uses `int32_t` for patch IDs. The following assert ensures
654 // that both the framework and the HAL use the same value for "no ID":
655 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
656 int32_t halPatchId = static_cast<int32_t>(*patch);
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800657
658 // Upon conversion, mix port configs contain audio configuration, while
659 // device port configs contain device address. This data is used to find
660 // or create HAL configs.
661 std::vector<AudioPortConfig> aidlSources, aidlSinks;
662 for (unsigned int i = 0; i < num_sources; ++i) {
663 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
664 sources[i].role, sources[i].type)) ==
665 ::aidl::android::AudioPortDirection::INPUT;
666 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
667 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
668 sources[i], isInput, 0)));
669 }
670 for (unsigned int i = 0; i < num_sinks; ++i) {
671 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
672 sinks[i].role, sinks[i].type)) ==
673 ::aidl::android::AudioPortDirection::INPUT;
674 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
675 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
676 sinks[i], isInput, 0)));
677 }
678 Cleanups cleanups;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800679 auto existingPatchIt = halPatchId != 0 ? mPatches.find(halPatchId): mPatches.end();
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800680 AudioPatch aidlPatch;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800681 if (existingPatchIt != mPatches.end()) {
682 aidlPatch = existingPatchIt->second;
683 aidlPatch.sourcePortConfigIds.clear();
684 aidlPatch.sinkPortConfigIds.clear();
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800685 }
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800686 ALOGD("%s: sources: %s, sinks: %s",
687 __func__, ::android::internal::ToString(aidlSources).c_str(),
688 ::android::internal::ToString(aidlSinks).c_str());
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800689 auto fillPortConfigs = [&](
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700690 const std::vector<AudioPortConfig>& configs,
691 const std::set<int32_t>& destinationPortIds,
692 std::vector<int32_t>* ids, std::set<int32_t>* portIds) -> status_t {
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800693 for (const auto& s : configs) {
694 AudioPortConfig portConfig;
695 bool created = false;
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700696 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
697 s, destinationPortIds, &portConfig, &created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800698 if (created) {
699 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, portConfig.id);
700 }
701 ids->push_back(portConfig.id);
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700702 if (portIds != nullptr) {
703 portIds->insert(portConfig.portId);
704 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800705 }
706 return OK;
707 };
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700708 // When looking up port configs, the destinationPortId is only used for mix ports.
709 // Thus, we process device port configs first, and look up the destination port ID from them.
710 bool sourceIsDevice = std::any_of(aidlSources.begin(), aidlSources.end(),
711 [](const auto& config) { return config.ext.getTag() == AudioPortExt::device; });
712 const std::vector<AudioPortConfig>& devicePortConfigs =
713 sourceIsDevice ? aidlSources : aidlSinks;
714 std::vector<int32_t>* devicePortConfigIds =
715 sourceIsDevice ? &aidlPatch.sourcePortConfigIds : &aidlPatch.sinkPortConfigIds;
716 const std::vector<AudioPortConfig>& mixPortConfigs =
717 sourceIsDevice ? aidlSinks : aidlSources;
718 std::vector<int32_t>* mixPortConfigIds =
719 sourceIsDevice ? &aidlPatch.sinkPortConfigIds : &aidlPatch.sourcePortConfigIds;
720 std::set<int32_t> devicePortIds;
721 RETURN_STATUS_IF_ERROR(fillPortConfigs(
722 devicePortConfigs, std::set<int32_t>(), devicePortConfigIds, &devicePortIds));
723 RETURN_STATUS_IF_ERROR(fillPortConfigs(
724 mixPortConfigs, devicePortIds, mixPortConfigIds, nullptr));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800725 if (existingPatchIt != mPatches.end()) {
726 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
727 mModule->setAudioPatch(aidlPatch, &aidlPatch)));
728 existingPatchIt->second = aidlPatch;
729 } else {
730 bool created = false;
731 RETURN_STATUS_IF_ERROR(findOrCreatePatch(aidlPatch, &aidlPatch, &created));
732 // Since no cleanup of the patch is needed, 'created' is ignored.
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800733 halPatchId = aidlPatch.id;
734 *patch = static_cast<audio_patch_handle_t>(halPatchId);
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800735 }
736 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000737 return OK;
738}
739
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800740status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800741 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000742 TIME_CHECK();
743 if (!mModule) return NO_INIT;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800744 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
745 if (patch == AUDIO_PATCH_HANDLE_NONE) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800746 return BAD_VALUE;
747 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800748 int32_t halPatchId = static_cast<int32_t>(patch);
749 auto patchIt = mPatches.find(halPatchId);
750 if (patchIt == mPatches.end()) {
751 ALOGE("%s: patch with id %d not found", __func__, halPatchId);
752 return BAD_VALUE;
753 }
754 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->resetAudioPatch(halPatchId)));
755 mPatches.erase(patchIt);
Shunkai Yao51202502022-12-12 06:11:46 +0000756 return OK;
757}
758
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700759status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
760 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000761 TIME_CHECK();
762 if (!mModule) return NO_INIT;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700763 if (port == nullptr) {
764 return BAD_VALUE;
765 }
766 audio_port_v7 portV7;
767 audio_populate_audio_port_v7(port, &portV7);
768 RETURN_STATUS_IF_ERROR(getAudioPort(&portV7));
769 return audio_populate_audio_port(&portV7, port) ? OK : BAD_VALUE;
770}
771
772status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
773 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
774 TIME_CHECK();
775 if (!mModule) return NO_INIT;
776 if (port == nullptr) {
777 return BAD_VALUE;
778 }
779 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
780 ::aidl::android::AudioPortDirection::INPUT;
781 auto aidlPort = VALUE_OR_RETURN_STATUS(
782 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
783 if (aidlPort.ext.getTag() != AudioPortExt::device) {
784 ALOGE("%s: provided port is not a device port (module %s): %s",
785 __func__, mInstance.c_str(), aidlPort.toString().c_str());
786 return BAD_VALUE;
787 }
788 const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
789 // It seems that we don't have to call HAL since all valid ports have been added either
790 // during initialization, or while handling connection of an external device.
791 auto portsIt = findPort(matchDevice);
792 if (portsIt == mPorts.end()) {
793 ALOGE("%s: device port for device %s is not found in the module %s",
794 __func__, matchDevice.toString().c_str(), mInstance.c_str());
795 return BAD_VALUE;
796 }
797 const int32_t fwkId = aidlPort.id;
798 aidlPort = portsIt->second;
799 aidlPort.id = fwkId;
800 *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
801 aidlPort, isInput));
802 return OK;
803}
804
805status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
806 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
807 TIME_CHECK();
808 if (!mModule) return NO_INIT;
809 if (config == nullptr) {
810 return BAD_VALUE;
811 }
812 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
813 config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
814 AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
815 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
816 *config, isInput, 0 /*portId*/));
817 AudioPortConfig portConfig;
818 bool created = false;
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700819 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
820 requestedPortConfig, std::set<int32_t>(), &portConfig, &created));
Shunkai Yao51202502022-12-12 06:11:46 +0000821 return OK;
822}
823
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800824MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
825 if (mMicrophones.status == Microphones::Status::UNKNOWN) {
826 TIME_CHECK();
827 std::vector<MicrophoneInfo> aidlInfo;
828 status_t status = statusTFromBinderStatus(mModule->getMicrophones(&aidlInfo));
829 if (status == OK) {
830 mMicrophones.status = Microphones::Status::QUERIED;
831 mMicrophones.info = std::move(aidlInfo);
832 } else if (status == INVALID_OPERATION) {
833 mMicrophones.status = Microphones::Status::NOT_SUPPORTED;
834 } else {
835 ALOGE("%s: Unexpected status from 'IModule.getMicrophones': %d", __func__, status);
836 return {};
837 }
838 }
839 if (mMicrophones.status == Microphones::Status::QUERIED) {
840 return &mMicrophones.info;
841 }
842 return {}; // NOT_SUPPORTED
843}
844
Shunkai Yao51202502022-12-12 06:11:46 +0000845status_t DeviceHalAidl::getMicrophones(
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800846 std::vector<audio_microphone_characteristic_t>* microphones) {
847 if (!microphones) {
848 return BAD_VALUE;
849 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000850 TIME_CHECK();
851 if (!mModule) return NO_INIT;
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800852 auto staticInfo = getMicrophoneInfo();
853 if (!staticInfo) return INVALID_OPERATION;
854 std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
855 emptyDynamicInfo.reserve(staticInfo->size());
856 std::transform(staticInfo->begin(), staticInfo->end(), std::back_inserter(emptyDynamicInfo),
857 [](const auto& info) { return MicrophoneDynamicInfo{ .id = info.id }; });
858 *microphones = VALUE_OR_RETURN_STATUS(
859 ::aidl::android::convertContainers<std::vector<audio_microphone_characteristic_t>>(
860 *staticInfo, emptyDynamicInfo,
861 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t)
862 );
Shunkai Yao51202502022-12-12 06:11:46 +0000863 return OK;
864}
865
Mikhail Naganov31d46652023-01-10 18:29:25 +0000866status_t DeviceHalAidl::addDeviceEffect(audio_port_handle_t device __unused,
867 sp<EffectHalInterface> effect) {
Shunkai Yao51202502022-12-12 06:11:46 +0000868 if (!effect) {
869 return BAD_VALUE;
870 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000871 TIME_CHECK();
872 if (!mModule) return NO_INIT;
873 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000874 return OK;
875}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000876status_t DeviceHalAidl::removeDeviceEffect(audio_port_handle_t device __unused,
Shunkai Yao51202502022-12-12 06:11:46 +0000877 sp<EffectHalInterface> effect) {
878 if (!effect) {
879 return BAD_VALUE;
880 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000881 TIME_CHECK();
882 if (!mModule) return NO_INIT;
883 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000884 return OK;
885}
886
887status_t DeviceHalAidl::getMmapPolicyInfos(
David Li9cf5e622023-03-21 00:51:10 +0800888 media::audio::common::AudioMMapPolicyType policyType,
889 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000890 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800891 AudioMMapPolicyType mmapPolicyType =
892 VALUE_OR_RETURN_STATUS(cpp2ndk_Enum<AudioMMapPolicyType>(policyType));
893
894 std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
895
896 if (status_t status = statusTFromBinderStatus(
897 mModule->getMmapPolicyInfos(mmapPolicyType, &mmapPolicyInfos)); status != OK) {
898 return status;
899 }
900
901 *policyInfos = VALUE_OR_RETURN_STATUS(
902 convertContainer<std::vector<media::audio::common::AudioMMapPolicyInfo>>(
903 mmapPolicyInfos, ndk2cpp_AudioMMapPolicyInfo));
Shunkai Yao51202502022-12-12 06:11:46 +0000904 return OK;
905}
906
907int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000908 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800909 int32_t mixerBurstCount = 0;
910 if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
911 return mixerBurstCount;
912 }
913 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000914}
915
916int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000917 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800918 int32_t hardwareBurstMinUsec = 0;
919 if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
920 return hardwareBurstMinUsec;
921 }
922 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000923}
924
925error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000926 TIME_CHECK();
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700927 if (!mModule) return NO_INIT;
928 int32_t aidlHwAvSync;
929 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
930 return VALUE_OR_RETURN_STATUS(
931 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +0000932}
933
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000934status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
935 TIME_CHECK();
936 if (!mModule) return NO_INIT;
937 return mModule->dump(fd, Args(args).args(), args.size());
David Li9cf5e622023-03-21 00:51:10 +0800938}
Shunkai Yao51202502022-12-12 06:11:46 +0000939
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700940int32_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000941 TIME_CHECK();
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700942 if (!mModule) return NO_INIT;
943 if (supports == nullptr) {
944 return BAD_VALUE;
945 }
946 return statusTFromBinderStatus(mModule->supportsVariableLatency(supports));
Shunkai Yao51202502022-12-12 06:11:46 +0000947}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000948
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100949status_t DeviceHalAidl::getSoundDoseInterface(const std::string& module,
950 ::ndk::SpAIBinder* soundDoseBinder) {
951 TIME_CHECK();
952 if (!mModule) return NO_INIT;
953 if (mSoundDose == nullptr) {
954 ndk::ScopedAStatus status = mModule->getSoundDose(&mSoundDose);
955 if (!status.isOk()) {
956 ALOGE("%s failed to return the sound dose interface for module %s: %s",
957 __func__,
958 module.c_str(),
959 status.getDescription().c_str());
960 return BAD_VALUE;
961 }
962 }
963 *soundDoseBinder = mSoundDose->asBinder();
964 ALOGI("%s using audio AIDL HAL sound dose interface", __func__);
965
966 return OK;
967}
968
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700969status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
970 TIME_CHECK();
971 if (!mModule) return NO_INIT;
972 if (port == nullptr) {
973 return BAD_VALUE;
974 }
975 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
976 ::aidl::android::AudioPortDirection::INPUT;
977 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
978 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
979 if (aidlPort.ext.getTag() != AudioPortExt::device) {
980 ALOGE("%s: provided port is not a device port (module %s): %s",
981 __func__, mInstance.c_str(), aidlPort.toString().c_str());
982 return BAD_VALUE;
983 }
984 if (connected) {
985 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
986 // Reset the device address to find the "template" port.
987 matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
988 auto portsIt = findPort(matchDevice);
989 if (portsIt == mPorts.end()) {
990 ALOGW("%s: device port for device %s is not found in the module %s",
991 __func__, matchDevice.toString().c_str(), mInstance.c_str());
992 return BAD_VALUE;
993 }
994 // Use the ID of the "template" port, use all the information from the provided port.
995 aidlPort.id = portsIt->first;
996 AudioPort connectedPort;
997 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
998 aidlPort, &connectedPort)));
999 const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
1000 LOG_ALWAYS_FATAL_IF(!inserted,
1001 "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
1002 __func__, mInstance.c_str(), connectedPort.toString().c_str(),
1003 it->second.toString().c_str());
1004 } else { // !connected
1005 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1006 auto portsIt = findPort(matchDevice);
1007 if (portsIt == mPorts.end()) {
1008 ALOGW("%s: device port for device %s is not found in the module %s",
1009 __func__, matchDevice.toString().c_str(), mInstance.c_str());
1010 return BAD_VALUE;
1011 }
1012 // Any streams opened on the external device must be closed by this time,
1013 // thus we can clean up patches and port configs that were created for them.
1014 resetUnusedPatchesAndPortConfigs();
1015 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
1016 portsIt->second.id)));
1017 mPorts.erase(portsIt);
1018 }
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001019 return updateRoutes();
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001020}
1021
1022status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
1023 TIME_CHECK();
1024 if (!mModule) return NO_INIT;
1025 ModuleDebug debug{ .simulateDeviceConnections = enabled };
1026 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
1027 // This is important to log as it affects HAL behavior.
1028 if (status == OK) {
1029 ALOGI("%s: set enabled: %d", __func__, enabled);
1030 } else {
1031 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
1032 }
1033 return status;
1034}
1035
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001036bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
1037 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1038 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1039}
1040
1041bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
1042 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1043 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1044 return p.portId == mDefaultInputPortId;
1045 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1046 return p.portId == mDefaultOutputPortId;
1047 }
1048 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1049}
1050
David Lia8f1e582023-03-30 21:08:06 +08001051status_t DeviceHalAidl::createOrUpdatePortConfig(
1052 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool* created) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001053 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001054 AudioPortConfig appliedPortConfig;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001055 bool applied = false;
1056 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001057 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001058 if (!applied) {
1059 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001060 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001061 if (!applied) {
1062 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001063 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001064 return NO_INIT;
1065 }
1066 }
David Lia8f1e582023-03-30 21:08:06 +08001067
1068 int32_t id = appliedPortConfig.id;
1069 if (requestedPortConfig.id != 0 && requestedPortConfig.id != id) {
1070 LOG_ALWAYS_FATAL("%s: requested port config id %d changed to %d", __func__,
1071 requestedPortConfig.id, id);
1072 }
1073
1074 auto [it, inserted] = mPortConfigs.insert_or_assign(std::move(id),
1075 std::move(appliedPortConfig));
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001076 *result = it;
David Lia8f1e582023-03-30 21:08:06 +08001077 *created = inserted;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001078 return OK;
1079}
1080
1081status_t DeviceHalAidl::findOrCreatePatch(
1082 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
1083 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
1084 requestedPatch.sourcePortConfigIds.end());
1085 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
1086 requestedPatch.sinkPortConfigIds.end());
1087 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
1088}
1089
1090status_t DeviceHalAidl::findOrCreatePatch(
1091 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
1092 AudioPatch* patch, bool* created) {
1093 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
1094 if (patchIt == mPatches.end()) {
1095 TIME_CHECK();
1096 AudioPatch requestedPatch, appliedPatch;
1097 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
1098 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
1099 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
1100 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
1101 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
1102 requestedPatch, &appliedPatch)));
1103 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
1104 *created = true;
1105 } else {
1106 *created = false;
1107 }
1108 *patch = patchIt->second;
1109 return OK;
1110}
1111
1112status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device,
1113 AudioPortConfig* portConfig, bool* created) {
1114 auto portConfigIt = findPortConfig(device);
1115 if (portConfigIt == mPortConfigs.end()) {
1116 auto portsIt = findPort(device);
1117 if (portsIt == mPorts.end()) {
1118 ALOGE("%s: device port for device %s is not found in the module %s",
1119 __func__, device.toString().c_str(), mInstance.c_str());
1120 return BAD_VALUE;
1121 }
1122 AudioPortConfig requestedPortConfig;
1123 requestedPortConfig.portId = portsIt->first;
David Lia8f1e582023-03-30 21:08:06 +08001124 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1125 created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001126 } else {
1127 *created = false;
1128 }
1129 *portConfig = portConfigIt->second;
1130 return OK;
1131}
1132
1133status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001134 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001135 AudioSource source, const std::set<int32_t>& destinationPortIds,
1136 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001137 // These flags get removed one by one in this order when retrying port finding.
1138 static const std::vector<AudioInputFlags> kOptionalInputFlags{
1139 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001140 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001141 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001142 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
1143 AudioIoFlags matchFlags = flags.value();
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001144 auto portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001145 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
1146 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
1147 if (!isBitPositionFlagSet(
1148 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
1149 ++optionalInputFlagsIt;
1150 continue;
1151 }
1152 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
1153 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001154 portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001155 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
1156 "retried with flags %s", __func__, config.toString().c_str(),
1157 flags.value().toString().c_str(), mInstance.c_str(),
1158 matchFlags.toString().c_str());
1159 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001160 if (portsIt == mPorts.end()) {
1161 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001162 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001163 mInstance.c_str());
1164 return BAD_VALUE;
1165 }
1166 AudioPortConfig requestedPortConfig;
1167 requestedPortConfig.portId = portsIt->first;
1168 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001169 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001170 if (matchFlags.getTag() == AudioIoFlags::Tag::input
1171 && source != AudioSource::SYS_RESERVED_INVALID) {
1172 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
1173 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
1174 }
David Lia8f1e582023-03-30 21:08:06 +08001175 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1176 created));
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001177 } else if (!flags.has_value()) {
1178 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
1179 "and was not created as flags are not specified",
1180 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
1181 return BAD_VALUE;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001182 } else {
David Lia8f1e582023-03-30 21:08:06 +08001183 AudioPortConfig requestedPortConfig = portConfigIt->second;
1184 if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
1185 AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
1186 if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
1187 source != AudioSource::SYS_RESERVED_INVALID) {
1188 mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
1189 }
1190 }
1191
1192 if (requestedPortConfig != portConfigIt->second) {
1193 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1194 created));
1195 } else {
1196 *created = false;
1197 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001198 }
1199 *portConfig = portConfigIt->second;
1200 return OK;
1201}
1202
1203status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001204 const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
1205 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001206 using Tag = AudioPortExt::Tag;
1207 if (requestedPortConfig.ext.getTag() == Tag::mix) {
1208 if (const auto& p = requestedPortConfig;
1209 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001210 !p.format.has_value()) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001211 ALOGW("%s: provided mix port config is not fully specified: %s",
1212 __func__, p.toString().c_str());
1213 return BAD_VALUE;
1214 }
1215 AudioConfig config;
1216 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001217 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
1218 AudioPortMixExtUseCase::Tag::source ?
1219 requestedPortConfig.ext.get<Tag::mix>().usecase.
1220 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001221 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001222 requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
1223 portConfig, created);
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001224 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
1225 return findOrCreatePortConfig(
1226 requestedPortConfig.ext.get<Tag::device>().device, portConfig, created);
1227 }
1228 ALOGW("%s: unsupported audio port config: %s",
1229 __func__, requestedPortConfig.toString().c_str());
1230 return BAD_VALUE;
1231}
1232
1233DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
1234 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
1235 return std::find_if(mPatches.begin(), mPatches.end(),
1236 [&](const auto& pair) {
1237 const auto& p = pair.second;
1238 std::set<int32_t> patchSrcs(
1239 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
1240 std::set<int32_t> patchSinks(
1241 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
1242 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
1243}
1244
1245DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001246 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1247 return mPorts.find(mDefaultInputPortId);
1248 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1249 return mPorts.find(mDefaultOutputPortId);
1250 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001251 return std::find_if(mPorts.begin(), mPorts.end(),
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001252 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001253}
1254
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001255
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001256DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001257 const AudioConfig& config, const AudioIoFlags& flags,
1258 const std::set<int32_t>& destinationPortIds) {
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001259 auto belongsToProfile = [&config](const AudioProfile& prof) {
1260 return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
1261 (config.base.channelMask.getTag() == AudioChannelLayout::none ||
1262 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
1263 config.base.channelMask) != prof.channelMasks.end()) &&
1264 (config.base.sampleRate == 0 ||
1265 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
1266 config.base.sampleRate) != prof.sampleRates.end());
1267 };
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001268 auto matcher = [&](const auto& pair) {
1269 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001270 return p.ext.getTag() == AudioPortExt::Tag::mix &&
1271 p.flags == flags &&
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001272 (destinationPortIds.empty() ||
1273 std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
1274 [&](const int32_t destId) { return mRoutingMatrix.count(
1275 std::make_pair(p.id, destId)) != 0; })) &&
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001276 (p.profiles.empty() ||
1277 std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
1278 p.profiles.end()); };
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001279 return std::find_if(mPorts.begin(), mPorts.end(), matcher);
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001280}
1281
1282DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001283 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001284 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001285}
1286
1287DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001288 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001289 using Tag = AudioPortExt::Tag;
1290 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
1291 [&](const auto& pair) {
1292 const auto& p = pair.second;
1293 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
1294 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
1295 !p.format.has_value() || !p.flags.has_value(),
1296 "%s: stored mix port config is not fully specified: %s",
1297 __func__, p.toString().c_str());
1298 return p.ext.getTag() == Tag::mix &&
1299 isConfigEqualToPortConfig(config, p) &&
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001300 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001301 p.ext.template get<Tag::mix>().handle == ioHandle; });
1302}
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001303
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001304void DeviceHalAidl::resetPatch(int32_t patchId) {
1305 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1306 mPatches.erase(it);
1307 TIME_CHECK();
1308 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1309 ALOGE("%s: error while resetting patch %d: %s",
1310 __func__, patchId, status.getDescription().c_str());
1311 }
1312 return;
1313 }
1314 ALOGE("%s: patch id %d not found", __func__, patchId);
1315}
1316
1317void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1318 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1319 mPortConfigs.erase(it);
1320 TIME_CHECK();
1321 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1322 !status.isOk()) {
1323 ALOGE("%s: error while resetting port config %d: %s",
1324 __func__, portConfigId, status.getDescription().c_str());
1325 }
1326 return;
1327 }
1328 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1329}
1330
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001331void DeviceHalAidl::resetUnusedPatches() {
1332 // Since patches can be created independently of streams via 'createAudioPatch',
1333 // here we only clean up patches for released streams.
1334 for (auto it = mStreams.begin(); it != mStreams.end(); ) {
1335 if (auto streamSp = it->first.promote(); streamSp) {
1336 ++it;
1337 } else {
1338 resetPatch(it->second);
1339 it = mStreams.erase(it);
1340 }
1341 }
1342}
1343
1344void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
1345 resetUnusedPatches();
1346 resetUnusedPortConfigs();
1347}
1348
1349void DeviceHalAidl::resetUnusedPortConfigs() {
1350 // The assumption is that port configs are used to create patches
1351 // (or to open streams, but that involves creation of patches, too). Thus,
1352 // orphaned port configs can and should be reset.
1353 std::set<int32_t> portConfigIds;
1354 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
1355 std::inserter(portConfigIds, portConfigIds.end()),
1356 [](const auto& pcPair) { return pcPair.first; });
1357 for (const auto& p : mPatches) {
1358 for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
1359 for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
1360 }
1361 for (int32_t id : portConfigIds) resetPortConfig(id);
1362}
1363
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001364status_t DeviceHalAidl::updateRoutes() {
1365 TIME_CHECK();
1366 std::vector<AudioRoute> routes;
1367 RETURN_STATUS_IF_ERROR(
1368 statusTFromBinderStatus(mModule->getAudioRoutes(&routes)));
1369 ALOGW_IF(routes.empty(), "%s: module %s returned an empty list of audio routes",
1370 __func__, mInstance.c_str());
1371 mRoutingMatrix.clear();
1372 for (const auto& r : routes) {
1373 for (auto portId : r.sourcePortIds) {
1374 mRoutingMatrix.emplace(r.sinkPortId, portId);
1375 mRoutingMatrix.emplace(portId, r.sinkPortId);
1376 }
1377 }
1378 return OK;
1379}
1380
Mikhail Naganovb0c55252023-02-08 16:59:41 -08001381void DeviceHalAidl::clearCallbacks(void* cookie) {
1382 std::lock_guard l(mLock);
1383 mCallbacks.erase(cookie);
1384}
1385
1386sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1387 return getCallbackImpl(cookie, &Callbacks::out);
1388}
1389
1390void DeviceHalAidl::setStreamOutCallback(
1391 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1392 setCallbackImpl(cookie, &Callbacks::out, cb);
1393}
1394
1395sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1396 void* cookie) {
1397 return getCallbackImpl(cookie, &Callbacks::event);
1398}
1399
1400void DeviceHalAidl::setStreamOutEventCallback(
1401 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1402 setCallbackImpl(cookie, &Callbacks::event, cb);
1403}
1404
1405sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1406 void* cookie) {
1407 return getCallbackImpl(cookie, &Callbacks::latency);
1408}
1409
1410void DeviceHalAidl::setStreamOutLatencyModeCallback(
1411 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1412 setCallbackImpl(cookie, &Callbacks::latency, cb);
1413}
1414
1415template<class C>
1416sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1417 std::lock_guard l(mLock);
1418 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1419 return ((it->second).*field).promote();
1420 }
1421 return nullptr;
1422}
1423template<class C>
1424void DeviceHalAidl::setCallbackImpl(
1425 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1426 std::lock_guard l(mLock);
1427 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1428 (it->second).*field = cb;
1429 }
1430}
1431
Mikhail Naganov31d46652023-01-10 18:29:25 +00001432} // namespace android