blob: 662c9641553c781cb50afa68b20bdf49b9636d0a [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 Naganov31d46652023-01-10 18:29:25 +0000940int32_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports __unused) {
941 TIME_CHECK();
Shunkai Yao51202502022-12-12 06:11:46 +0000942 ALOGE("%s not implemented yet", __func__);
943 return INVALID_OPERATION;
944}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000945
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100946status_t DeviceHalAidl::getSoundDoseInterface(const std::string& module,
947 ::ndk::SpAIBinder* soundDoseBinder) {
948 TIME_CHECK();
949 if (!mModule) return NO_INIT;
950 if (mSoundDose == nullptr) {
951 ndk::ScopedAStatus status = mModule->getSoundDose(&mSoundDose);
952 if (!status.isOk()) {
953 ALOGE("%s failed to return the sound dose interface for module %s: %s",
954 __func__,
955 module.c_str(),
956 status.getDescription().c_str());
957 return BAD_VALUE;
958 }
959 }
960 *soundDoseBinder = mSoundDose->asBinder();
961 ALOGI("%s using audio AIDL HAL sound dose interface", __func__);
962
963 return OK;
964}
965
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700966status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
967 TIME_CHECK();
968 if (!mModule) return NO_INIT;
969 if (port == nullptr) {
970 return BAD_VALUE;
971 }
972 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
973 ::aidl::android::AudioPortDirection::INPUT;
974 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
975 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
976 if (aidlPort.ext.getTag() != AudioPortExt::device) {
977 ALOGE("%s: provided port is not a device port (module %s): %s",
978 __func__, mInstance.c_str(), aidlPort.toString().c_str());
979 return BAD_VALUE;
980 }
981 if (connected) {
982 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
983 // Reset the device address to find the "template" port.
984 matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
985 auto portsIt = findPort(matchDevice);
986 if (portsIt == mPorts.end()) {
987 ALOGW("%s: device port for device %s is not found in the module %s",
988 __func__, matchDevice.toString().c_str(), mInstance.c_str());
989 return BAD_VALUE;
990 }
991 // Use the ID of the "template" port, use all the information from the provided port.
992 aidlPort.id = portsIt->first;
993 AudioPort connectedPort;
994 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
995 aidlPort, &connectedPort)));
996 const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
997 LOG_ALWAYS_FATAL_IF(!inserted,
998 "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
999 __func__, mInstance.c_str(), connectedPort.toString().c_str(),
1000 it->second.toString().c_str());
1001 } else { // !connected
1002 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1003 auto portsIt = findPort(matchDevice);
1004 if (portsIt == mPorts.end()) {
1005 ALOGW("%s: device port for device %s is not found in the module %s",
1006 __func__, matchDevice.toString().c_str(), mInstance.c_str());
1007 return BAD_VALUE;
1008 }
1009 // Any streams opened on the external device must be closed by this time,
1010 // thus we can clean up patches and port configs that were created for them.
1011 resetUnusedPatchesAndPortConfigs();
1012 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
1013 portsIt->second.id)));
1014 mPorts.erase(portsIt);
1015 }
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001016 return updateRoutes();
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001017}
1018
1019status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
1020 TIME_CHECK();
1021 if (!mModule) return NO_INIT;
1022 ModuleDebug debug{ .simulateDeviceConnections = enabled };
1023 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
1024 // This is important to log as it affects HAL behavior.
1025 if (status == OK) {
1026 ALOGI("%s: set enabled: %d", __func__, enabled);
1027 } else {
1028 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
1029 }
1030 return status;
1031}
1032
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001033bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
1034 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1035 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1036}
1037
1038bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
1039 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1040 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1041 return p.portId == mDefaultInputPortId;
1042 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1043 return p.portId == mDefaultOutputPortId;
1044 }
1045 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1046}
1047
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001048status_t DeviceHalAidl::createPortConfig(
1049 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001050 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001051 AudioPortConfig appliedPortConfig;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001052 bool applied = false;
1053 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001054 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001055 if (!applied) {
1056 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001057 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001058 if (!applied) {
1059 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001060 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001061 return NO_INIT;
1062 }
1063 }
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001064 auto id = appliedPortConfig.id;
1065 auto [it, inserted] = mPortConfigs.emplace(std::move(id), std::move(appliedPortConfig));
1066 LOG_ALWAYS_FATAL_IF(!inserted, "%s: port config with id %d already exists",
1067 __func__, it->first);
1068 *result = it;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001069 return OK;
1070}
1071
1072status_t DeviceHalAidl::findOrCreatePatch(
1073 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
1074 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
1075 requestedPatch.sourcePortConfigIds.end());
1076 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
1077 requestedPatch.sinkPortConfigIds.end());
1078 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
1079}
1080
1081status_t DeviceHalAidl::findOrCreatePatch(
1082 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
1083 AudioPatch* patch, bool* created) {
1084 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
1085 if (patchIt == mPatches.end()) {
1086 TIME_CHECK();
1087 AudioPatch requestedPatch, appliedPatch;
1088 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
1089 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
1090 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
1091 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
1092 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
1093 requestedPatch, &appliedPatch)));
1094 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
1095 *created = true;
1096 } else {
1097 *created = false;
1098 }
1099 *patch = patchIt->second;
1100 return OK;
1101}
1102
1103status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device,
1104 AudioPortConfig* portConfig, bool* created) {
1105 auto portConfigIt = findPortConfig(device);
1106 if (portConfigIt == mPortConfigs.end()) {
1107 auto portsIt = findPort(device);
1108 if (portsIt == mPorts.end()) {
1109 ALOGE("%s: device port for device %s is not found in the module %s",
1110 __func__, device.toString().c_str(), mInstance.c_str());
1111 return BAD_VALUE;
1112 }
1113 AudioPortConfig requestedPortConfig;
1114 requestedPortConfig.portId = portsIt->first;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001115 RETURN_STATUS_IF_ERROR(createPortConfig(requestedPortConfig, &portConfigIt));
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001116 *created = true;
1117 } else {
1118 *created = false;
1119 }
1120 *portConfig = portConfigIt->second;
1121 return OK;
1122}
1123
1124status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001125 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001126 AudioSource source, const std::set<int32_t>& destinationPortIds,
1127 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001128 // These flags get removed one by one in this order when retrying port finding.
1129 static const std::vector<AudioInputFlags> kOptionalInputFlags{
1130 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001131 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001132 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001133 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
1134 AudioIoFlags matchFlags = flags.value();
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001135 auto portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001136 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
1137 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
1138 if (!isBitPositionFlagSet(
1139 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
1140 ++optionalInputFlagsIt;
1141 continue;
1142 }
1143 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
1144 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001145 portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001146 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
1147 "retried with flags %s", __func__, config.toString().c_str(),
1148 flags.value().toString().c_str(), mInstance.c_str(),
1149 matchFlags.toString().c_str());
1150 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001151 if (portsIt == mPorts.end()) {
1152 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001153 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001154 mInstance.c_str());
1155 return BAD_VALUE;
1156 }
1157 AudioPortConfig requestedPortConfig;
1158 requestedPortConfig.portId = portsIt->first;
1159 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001160 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001161 if (matchFlags.getTag() == AudioIoFlags::Tag::input
1162 && source != AudioSource::SYS_RESERVED_INVALID) {
1163 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
1164 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
1165 }
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001166 RETURN_STATUS_IF_ERROR(createPortConfig(requestedPortConfig, &portConfigIt));
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001167 *created = true;
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001168 } else if (!flags.has_value()) {
1169 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
1170 "and was not created as flags are not specified",
1171 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
1172 return BAD_VALUE;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001173 } else {
1174 *created = false;
1175 }
1176 *portConfig = portConfigIt->second;
1177 return OK;
1178}
1179
1180status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001181 const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
1182 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001183 using Tag = AudioPortExt::Tag;
1184 if (requestedPortConfig.ext.getTag() == Tag::mix) {
1185 if (const auto& p = requestedPortConfig;
1186 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001187 !p.format.has_value()) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001188 ALOGW("%s: provided mix port config is not fully specified: %s",
1189 __func__, p.toString().c_str());
1190 return BAD_VALUE;
1191 }
1192 AudioConfig config;
1193 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001194 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
1195 AudioPortMixExtUseCase::Tag::source ?
1196 requestedPortConfig.ext.get<Tag::mix>().usecase.
1197 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001198 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001199 requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
1200 portConfig, created);
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001201 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
1202 return findOrCreatePortConfig(
1203 requestedPortConfig.ext.get<Tag::device>().device, portConfig, created);
1204 }
1205 ALOGW("%s: unsupported audio port config: %s",
1206 __func__, requestedPortConfig.toString().c_str());
1207 return BAD_VALUE;
1208}
1209
1210DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
1211 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
1212 return std::find_if(mPatches.begin(), mPatches.end(),
1213 [&](const auto& pair) {
1214 const auto& p = pair.second;
1215 std::set<int32_t> patchSrcs(
1216 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
1217 std::set<int32_t> patchSinks(
1218 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
1219 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
1220}
1221
1222DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001223 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1224 return mPorts.find(mDefaultInputPortId);
1225 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1226 return mPorts.find(mDefaultOutputPortId);
1227 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001228 return std::find_if(mPorts.begin(), mPorts.end(),
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001229 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001230}
1231
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001232
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001233DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001234 const AudioConfig& config, const AudioIoFlags& flags,
1235 const std::set<int32_t>& destinationPortIds) {
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001236 auto belongsToProfile = [&config](const AudioProfile& prof) {
1237 return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
1238 (config.base.channelMask.getTag() == AudioChannelLayout::none ||
1239 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
1240 config.base.channelMask) != prof.channelMasks.end()) &&
1241 (config.base.sampleRate == 0 ||
1242 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
1243 config.base.sampleRate) != prof.sampleRates.end());
1244 };
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001245 auto matcher = [&](const auto& pair) {
1246 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001247 return p.ext.getTag() == AudioPortExt::Tag::mix &&
1248 p.flags == flags &&
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001249 (destinationPortIds.empty() ||
1250 std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
1251 [&](const int32_t destId) { return mRoutingMatrix.count(
1252 std::make_pair(p.id, destId)) != 0; })) &&
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001253 (p.profiles.empty() ||
1254 std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
1255 p.profiles.end()); };
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001256 return std::find_if(mPorts.begin(), mPorts.end(), matcher);
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001257}
1258
1259DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001260 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001261 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001262}
1263
1264DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001265 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001266 using Tag = AudioPortExt::Tag;
1267 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
1268 [&](const auto& pair) {
1269 const auto& p = pair.second;
1270 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
1271 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
1272 !p.format.has_value() || !p.flags.has_value(),
1273 "%s: stored mix port config is not fully specified: %s",
1274 __func__, p.toString().c_str());
1275 return p.ext.getTag() == Tag::mix &&
1276 isConfigEqualToPortConfig(config, p) &&
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001277 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001278 p.ext.template get<Tag::mix>().handle == ioHandle; });
1279}
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001280
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001281void DeviceHalAidl::resetPatch(int32_t patchId) {
1282 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1283 mPatches.erase(it);
1284 TIME_CHECK();
1285 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1286 ALOGE("%s: error while resetting patch %d: %s",
1287 __func__, patchId, status.getDescription().c_str());
1288 }
1289 return;
1290 }
1291 ALOGE("%s: patch id %d not found", __func__, patchId);
1292}
1293
1294void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1295 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1296 mPortConfigs.erase(it);
1297 TIME_CHECK();
1298 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1299 !status.isOk()) {
1300 ALOGE("%s: error while resetting port config %d: %s",
1301 __func__, portConfigId, status.getDescription().c_str());
1302 }
1303 return;
1304 }
1305 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1306}
1307
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001308void DeviceHalAidl::resetUnusedPatches() {
1309 // Since patches can be created independently of streams via 'createAudioPatch',
1310 // here we only clean up patches for released streams.
1311 for (auto it = mStreams.begin(); it != mStreams.end(); ) {
1312 if (auto streamSp = it->first.promote(); streamSp) {
1313 ++it;
1314 } else {
1315 resetPatch(it->second);
1316 it = mStreams.erase(it);
1317 }
1318 }
1319}
1320
1321void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
1322 resetUnusedPatches();
1323 resetUnusedPortConfigs();
1324}
1325
1326void DeviceHalAidl::resetUnusedPortConfigs() {
1327 // The assumption is that port configs are used to create patches
1328 // (or to open streams, but that involves creation of patches, too). Thus,
1329 // orphaned port configs can and should be reset.
1330 std::set<int32_t> portConfigIds;
1331 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
1332 std::inserter(portConfigIds, portConfigIds.end()),
1333 [](const auto& pcPair) { return pcPair.first; });
1334 for (const auto& p : mPatches) {
1335 for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
1336 for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
1337 }
1338 for (int32_t id : portConfigIds) resetPortConfig(id);
1339}
1340
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001341status_t DeviceHalAidl::updateRoutes() {
1342 TIME_CHECK();
1343 std::vector<AudioRoute> routes;
1344 RETURN_STATUS_IF_ERROR(
1345 statusTFromBinderStatus(mModule->getAudioRoutes(&routes)));
1346 ALOGW_IF(routes.empty(), "%s: module %s returned an empty list of audio routes",
1347 __func__, mInstance.c_str());
1348 mRoutingMatrix.clear();
1349 for (const auto& r : routes) {
1350 for (auto portId : r.sourcePortIds) {
1351 mRoutingMatrix.emplace(r.sinkPortId, portId);
1352 mRoutingMatrix.emplace(portId, r.sinkPortId);
1353 }
1354 }
1355 return OK;
1356}
1357
Mikhail Naganovb0c55252023-02-08 16:59:41 -08001358void DeviceHalAidl::clearCallbacks(void* cookie) {
1359 std::lock_guard l(mLock);
1360 mCallbacks.erase(cookie);
1361}
1362
1363sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1364 return getCallbackImpl(cookie, &Callbacks::out);
1365}
1366
1367void DeviceHalAidl::setStreamOutCallback(
1368 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1369 setCallbackImpl(cookie, &Callbacks::out, cb);
1370}
1371
1372sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1373 void* cookie) {
1374 return getCallbackImpl(cookie, &Callbacks::event);
1375}
1376
1377void DeviceHalAidl::setStreamOutEventCallback(
1378 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1379 setCallbackImpl(cookie, &Callbacks::event, cb);
1380}
1381
1382sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1383 void* cookie) {
1384 return getCallbackImpl(cookie, &Callbacks::latency);
1385}
1386
1387void DeviceHalAidl::setStreamOutLatencyModeCallback(
1388 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1389 setCallbackImpl(cookie, &Callbacks::latency, cb);
1390}
1391
1392template<class C>
1393sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1394 std::lock_guard l(mLock);
1395 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1396 return ((it->second).*field).promote();
1397 }
1398 return nullptr;
1399}
1400template<class C>
1401void DeviceHalAidl::setCallbackImpl(
1402 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1403 std::lock_guard l(mLock);
1404 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1405 (it->second).*field = cb;
1406 }
1407}
1408
Mikhail Naganov31d46652023-01-10 18:29:25 +00001409} // namespace android