blob: 3894cbfa069b484253e093c2e54c5d627253ed0d [file] [log] [blame]
Shunkai Yao51202502022-12-12 06:11:46 +00001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "DeviceHalAidl"
Mikhail Naganov89a9f742023-01-30 12:33:18 -080018// #define LOG_NDEBUG 0
Shunkai Yao51202502022-12-12 06:11:46 +000019
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080020#include <algorithm>
21#include <forward_list>
22
Mikhail Naganovdfd594e2023-02-08 16:59:41 -080023#include <aidl/android/hardware/audio/core/BnStreamCallback.h>
24#include <aidl/android/hardware/audio/core/BnStreamOutEventCallback.h>
Mikhail Naganovfab697c2023-01-11 19:33:13 +000025#include <aidl/android/hardware/audio/core/StreamDescriptor.h>
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 Naganov89a9f742023-01-30 12:33:18 -080032#include <Utils.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000033#include <utils/Log.h>
Shunkai Yao51202502022-12-12 06:11:46 +000034
Mikhail Naganov31d46652023-01-10 18:29:25 +000035#include "DeviceHalAidl.h"
36#include "StreamHalAidl.h"
37
Mikhail Naganovfab697c2023-01-11 19:33:13 +000038using aidl::android::aidl_utils::statusTFromBinderStatus;
Mikhail Naganove93a0862023-03-15 17:06:59 -070039using aidl::android::media::audio::common::AudioChannelLayout;
Mikhail Naganov5b1eed12023-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 Naganov89a9f742023-01-30 12:33:18 -080043using aidl::android::media::audio::common::AudioDeviceType;
Mikhail Naganove93a0862023-03-15 17:06:59 -070044using aidl::android::media::audio::common::AudioFormatType;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080045using aidl::android::media::audio::common::AudioInputFlags;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080046using aidl::android::media::audio::common::AudioIoFlags;
Mikhail Naganovdfd594e2023-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 Naganov5b1eed12023-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 Naganov89a9f742023-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 Naganove93a0862023-03-15 17:06:59 -070059using aidl::android::media::audio::common::AudioProfile;
Mikhail Naganov5b1eed12023-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 Naganove93a0862023-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 Naganov5b1eed12023-01-25 11:29:11 -080069using aidl::android::hardware::audio::common::RecordTrackMetadata;
70using aidl::android::hardware::audio::core::AudioPatch;
Mikhail Naganov289468a2023-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 Naganove93a0862023-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 Naganov5b1eed12023-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 Naganov5b1eed12023-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 Naganov5b1eed12023-01-25 11:29:11 -0800176 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000177 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov5b1eed12023-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 Naganov89a9f742023-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 Naganov289468a2023-03-29 10:06:15 -0700200 RETURN_STATUS_IF_ERROR(updateRoutes());
Mikhail Naganov5b1eed12023-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 Naganov5b1eed12023-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 Naganov89a9f742023-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 Naganov89a9f742023-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 Naganove93a0862023-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 Naganove93a0862023-03-15 17:06:59 -0700344 &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov89a9f742023-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 Naganov5b1eed12023-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 Naganov89a9f742023-01-30 12:33:18 -0800354 Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
Mikhail Naganove93a0862023-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 Naganov5b1eed12023-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 Naganov289468a2023-03-29 10:06:15 -0700370 std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800371 if (created) {
372 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
373 }
374 setConfigFromPortConfig(aidlConfig, *mixPortConfig);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800375 if (isInput) {
376 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700377 {devicePortConfig.id}, {mixPortConfig->id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800378 } else {
379 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700380 {mixPortConfig->id}, {devicePortConfig.id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800381 }
382 if (created) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700383 cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, aidlPatch->id);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800384 }
385 if (aidlConfig->frameCount <= 0) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700386 aidlConfig->frameCount = aidlPatch->minimumStreamBufferSizeFrames;
Mikhail Naganov5b1eed12023-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 Naganovdfd594e2023-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 Naganov5b1eed12023-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 Naganov89a9f742023-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 Naganov5b1eed12023-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 Naganove93a0862023-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 Naganove93a0862023-03-15 17:06:59 -0700535 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800536 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
537 args.portConfigId = mixPortConfig.id;
Mikhail Naganovdfd594e2023-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 Naganov5b1eed12023-01-25 11:29:11 -0800549 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800550 args.eventCallback = eventCb;
Mikhail Naganov5b1eed12023-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 Naganov89a9f742023-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 Naganove93a0862023-03-15 17:06:59 -0700559 *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800560 std::move(ret.stream), this /*callbackBroker*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700561 mStreams.insert(std::pair(*outStream, aidlPatch.id));
Mikhail Naganovdfd594e2023-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 Naganov5b1eed12023-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 Naganov5b1eed12023-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 Naganov89a9f742023-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 Naganov5b1eed12023-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 Naganove93a0862023-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 Naganove93a0862023-03-15 17:06:59 -0700600 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-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 Naganov89a9f742023-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 Naganove93a0862023-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 Naganove93a0862023-03-15 17:06:59 -0700622 mStreams.insert(std::pair(*inStream, aidlPatch.id));
Mikhail Naganov5b1eed12023-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 Naganov5b1eed12023-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 Naganov89a9f742023-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 Naganov5b1eed12023-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 Naganov5b1eed12023-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 Naganov5b1eed12023-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 Naganov5b1eed12023-01-25 11:29:11 -0800685 }
Mikhail Naganov89a9f742023-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 Naganov5b1eed12023-01-25 11:29:11 -0800689 auto fillPortConfigs = [&](
Mikhail Naganov289468a2023-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 Naganov5b1eed12023-01-25 11:29:11 -0800693 for (const auto& s : configs) {
694 AudioPortConfig portConfig;
695 bool created = false;
Mikhail Naganov289468a2023-03-29 10:06:15 -0700696 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
697 s, destinationPortIds, &portConfig, &created));
Mikhail Naganov5b1eed12023-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 Naganov289468a2023-03-29 10:06:15 -0700702 if (portIds != nullptr) {
703 portIds->insert(portConfig.portId);
704 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800705 }
706 return OK;
707 };
Mikhail Naganov289468a2023-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 Naganov5b1eed12023-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 Naganov5b1eed12023-01-25 11:29:11 -0800735 }
736 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000737 return OK;
738}
739
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800740status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov89a9f742023-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 Naganov5b1eed12023-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 Naganove93a0862023-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 Naganove93a0862023-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 Naganov289468a2023-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
Mikhail Naganove93a0862023-03-15 17:06:59 -0700946status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
947 TIME_CHECK();
948 if (!mModule) return NO_INIT;
949 if (port == nullptr) {
950 return BAD_VALUE;
951 }
952 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
953 ::aidl::android::AudioPortDirection::INPUT;
954 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
955 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
956 if (aidlPort.ext.getTag() != AudioPortExt::device) {
957 ALOGE("%s: provided port is not a device port (module %s): %s",
958 __func__, mInstance.c_str(), aidlPort.toString().c_str());
959 return BAD_VALUE;
960 }
961 if (connected) {
962 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
963 // Reset the device address to find the "template" port.
964 matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
965 auto portsIt = findPort(matchDevice);
966 if (portsIt == mPorts.end()) {
967 ALOGW("%s: device port for device %s is not found in the module %s",
968 __func__, matchDevice.toString().c_str(), mInstance.c_str());
969 return BAD_VALUE;
970 }
971 // Use the ID of the "template" port, use all the information from the provided port.
972 aidlPort.id = portsIt->first;
973 AudioPort connectedPort;
974 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
975 aidlPort, &connectedPort)));
976 const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
977 LOG_ALWAYS_FATAL_IF(!inserted,
978 "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
979 __func__, mInstance.c_str(), connectedPort.toString().c_str(),
980 it->second.toString().c_str());
981 } else { // !connected
982 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
983 auto portsIt = findPort(matchDevice);
984 if (portsIt == mPorts.end()) {
985 ALOGW("%s: device port for device %s is not found in the module %s",
986 __func__, matchDevice.toString().c_str(), mInstance.c_str());
987 return BAD_VALUE;
988 }
989 // Any streams opened on the external device must be closed by this time,
990 // thus we can clean up patches and port configs that were created for them.
991 resetUnusedPatchesAndPortConfigs();
992 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
993 portsIt->second.id)));
994 mPorts.erase(portsIt);
995 }
Mikhail Naganov289468a2023-03-29 10:06:15 -0700996 return updateRoutes();
Mikhail Naganove93a0862023-03-15 17:06:59 -0700997}
998
999status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
1000 TIME_CHECK();
1001 if (!mModule) return NO_INIT;
1002 ModuleDebug debug{ .simulateDeviceConnections = enabled };
1003 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
1004 // This is important to log as it affects HAL behavior.
1005 if (status == OK) {
1006 ALOGI("%s: set enabled: %d", __func__, enabled);
1007 } else {
1008 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
1009 }
1010 return status;
1011}
1012
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001013bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
1014 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1015 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1016}
1017
1018bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
1019 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1020 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1021 return p.portId == mDefaultInputPortId;
1022 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1023 return p.portId == mDefaultOutputPortId;
1024 }
1025 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1026}
1027
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001028status_t DeviceHalAidl::createPortConfig(
1029 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001030 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001031 AudioPortConfig appliedPortConfig;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001032 bool applied = false;
1033 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001034 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001035 if (!applied) {
1036 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001037 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001038 if (!applied) {
1039 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001040 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001041 return NO_INIT;
1042 }
1043 }
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001044 auto id = appliedPortConfig.id;
1045 auto [it, inserted] = mPortConfigs.emplace(std::move(id), std::move(appliedPortConfig));
1046 LOG_ALWAYS_FATAL_IF(!inserted, "%s: port config with id %d already exists",
1047 __func__, it->first);
1048 *result = it;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001049 return OK;
1050}
1051
1052status_t DeviceHalAidl::findOrCreatePatch(
1053 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
1054 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
1055 requestedPatch.sourcePortConfigIds.end());
1056 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
1057 requestedPatch.sinkPortConfigIds.end());
1058 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
1059}
1060
1061status_t DeviceHalAidl::findOrCreatePatch(
1062 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
1063 AudioPatch* patch, bool* created) {
1064 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
1065 if (patchIt == mPatches.end()) {
1066 TIME_CHECK();
1067 AudioPatch requestedPatch, appliedPatch;
1068 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
1069 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
1070 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
1071 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
1072 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
1073 requestedPatch, &appliedPatch)));
1074 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
1075 *created = true;
1076 } else {
1077 *created = false;
1078 }
1079 *patch = patchIt->second;
1080 return OK;
1081}
1082
1083status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device,
1084 AudioPortConfig* portConfig, bool* created) {
1085 auto portConfigIt = findPortConfig(device);
1086 if (portConfigIt == mPortConfigs.end()) {
1087 auto portsIt = findPort(device);
1088 if (portsIt == mPorts.end()) {
1089 ALOGE("%s: device port for device %s is not found in the module %s",
1090 __func__, device.toString().c_str(), mInstance.c_str());
1091 return BAD_VALUE;
1092 }
1093 AudioPortConfig requestedPortConfig;
1094 requestedPortConfig.portId = portsIt->first;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001095 RETURN_STATUS_IF_ERROR(createPortConfig(requestedPortConfig, &portConfigIt));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001096 *created = true;
1097 } else {
1098 *created = false;
1099 }
1100 *portConfig = portConfigIt->second;
1101 return OK;
1102}
1103
1104status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001105 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001106 AudioSource source, const std::set<int32_t>& destinationPortIds,
1107 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001108 // These flags get removed one by one in this order when retrying port finding.
1109 static const std::vector<AudioInputFlags> kOptionalInputFlags{
1110 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001111 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001112 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001113 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
1114 AudioIoFlags matchFlags = flags.value();
Mikhail Naganov289468a2023-03-29 10:06:15 -07001115 auto portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001116 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
1117 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
1118 if (!isBitPositionFlagSet(
1119 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
1120 ++optionalInputFlagsIt;
1121 continue;
1122 }
1123 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
1124 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
Mikhail Naganov289468a2023-03-29 10:06:15 -07001125 portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001126 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
1127 "retried with flags %s", __func__, config.toString().c_str(),
1128 flags.value().toString().c_str(), mInstance.c_str(),
1129 matchFlags.toString().c_str());
1130 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001131 if (portsIt == mPorts.end()) {
1132 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001133 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001134 mInstance.c_str());
1135 return BAD_VALUE;
1136 }
1137 AudioPortConfig requestedPortConfig;
1138 requestedPortConfig.portId = portsIt->first;
1139 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001140 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001141 if (matchFlags.getTag() == AudioIoFlags::Tag::input
1142 && source != AudioSource::SYS_RESERVED_INVALID) {
1143 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
1144 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
1145 }
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001146 RETURN_STATUS_IF_ERROR(createPortConfig(requestedPortConfig, &portConfigIt));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001147 *created = true;
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001148 } else if (!flags.has_value()) {
1149 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
1150 "and was not created as flags are not specified",
1151 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
1152 return BAD_VALUE;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001153 } else {
1154 *created = false;
1155 }
1156 *portConfig = portConfigIt->second;
1157 return OK;
1158}
1159
1160status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001161 const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
1162 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001163 using Tag = AudioPortExt::Tag;
1164 if (requestedPortConfig.ext.getTag() == Tag::mix) {
1165 if (const auto& p = requestedPortConfig;
1166 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001167 !p.format.has_value()) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001168 ALOGW("%s: provided mix port config is not fully specified: %s",
1169 __func__, p.toString().c_str());
1170 return BAD_VALUE;
1171 }
1172 AudioConfig config;
1173 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001174 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
1175 AudioPortMixExtUseCase::Tag::source ?
1176 requestedPortConfig.ext.get<Tag::mix>().usecase.
1177 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001178 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001179 requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
1180 portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001181 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
1182 return findOrCreatePortConfig(
1183 requestedPortConfig.ext.get<Tag::device>().device, portConfig, created);
1184 }
1185 ALOGW("%s: unsupported audio port config: %s",
1186 __func__, requestedPortConfig.toString().c_str());
1187 return BAD_VALUE;
1188}
1189
1190DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
1191 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
1192 return std::find_if(mPatches.begin(), mPatches.end(),
1193 [&](const auto& pair) {
1194 const auto& p = pair.second;
1195 std::set<int32_t> patchSrcs(
1196 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
1197 std::set<int32_t> patchSinks(
1198 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
1199 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
1200}
1201
1202DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001203 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1204 return mPorts.find(mDefaultInputPortId);
1205 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1206 return mPorts.find(mDefaultOutputPortId);
1207 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001208 return std::find_if(mPorts.begin(), mPorts.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001209 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001210}
1211
Mikhail Naganov289468a2023-03-29 10:06:15 -07001212
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001213DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001214 const AudioConfig& config, const AudioIoFlags& flags,
1215 const std::set<int32_t>& destinationPortIds) {
Mikhail Naganove93a0862023-03-15 17:06:59 -07001216 auto belongsToProfile = [&config](const AudioProfile& prof) {
1217 return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
1218 (config.base.channelMask.getTag() == AudioChannelLayout::none ||
1219 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
1220 config.base.channelMask) != prof.channelMasks.end()) &&
1221 (config.base.sampleRate == 0 ||
1222 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
1223 config.base.sampleRate) != prof.sampleRates.end());
1224 };
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001225 auto matcher = [&](const auto& pair) {
1226 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001227 return p.ext.getTag() == AudioPortExt::Tag::mix &&
1228 p.flags == flags &&
Mikhail Naganov289468a2023-03-29 10:06:15 -07001229 (destinationPortIds.empty() ||
1230 std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
1231 [&](const int32_t destId) { return mRoutingMatrix.count(
1232 std::make_pair(p.id, destId)) != 0; })) &&
Mikhail Naganove93a0862023-03-15 17:06:59 -07001233 (p.profiles.empty() ||
1234 std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
1235 p.profiles.end()); };
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001236 return std::find_if(mPorts.begin(), mPorts.end(), matcher);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001237}
1238
1239DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001240 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001241 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001242}
1243
1244DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001245 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001246 using Tag = AudioPortExt::Tag;
1247 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
1248 [&](const auto& pair) {
1249 const auto& p = pair.second;
1250 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
1251 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
1252 !p.format.has_value() || !p.flags.has_value(),
1253 "%s: stored mix port config is not fully specified: %s",
1254 __func__, p.toString().c_str());
1255 return p.ext.getTag() == Tag::mix &&
1256 isConfigEqualToPortConfig(config, p) &&
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001257 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001258 p.ext.template get<Tag::mix>().handle == ioHandle; });
1259}
Mikhail Naganove93a0862023-03-15 17:06:59 -07001260
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001261void DeviceHalAidl::resetPatch(int32_t patchId) {
1262 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1263 mPatches.erase(it);
1264 TIME_CHECK();
1265 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1266 ALOGE("%s: error while resetting patch %d: %s",
1267 __func__, patchId, status.getDescription().c_str());
1268 }
1269 return;
1270 }
1271 ALOGE("%s: patch id %d not found", __func__, patchId);
1272}
1273
1274void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1275 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1276 mPortConfigs.erase(it);
1277 TIME_CHECK();
1278 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1279 !status.isOk()) {
1280 ALOGE("%s: error while resetting port config %d: %s",
1281 __func__, portConfigId, status.getDescription().c_str());
1282 }
1283 return;
1284 }
1285 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1286}
1287
Mikhail Naganove93a0862023-03-15 17:06:59 -07001288void DeviceHalAidl::resetUnusedPatches() {
1289 // Since patches can be created independently of streams via 'createAudioPatch',
1290 // here we only clean up patches for released streams.
1291 for (auto it = mStreams.begin(); it != mStreams.end(); ) {
1292 if (auto streamSp = it->first.promote(); streamSp) {
1293 ++it;
1294 } else {
1295 resetPatch(it->second);
1296 it = mStreams.erase(it);
1297 }
1298 }
1299}
1300
1301void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
1302 resetUnusedPatches();
1303 resetUnusedPortConfigs();
1304}
1305
1306void DeviceHalAidl::resetUnusedPortConfigs() {
1307 // The assumption is that port configs are used to create patches
1308 // (or to open streams, but that involves creation of patches, too). Thus,
1309 // orphaned port configs can and should be reset.
1310 std::set<int32_t> portConfigIds;
1311 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
1312 std::inserter(portConfigIds, portConfigIds.end()),
1313 [](const auto& pcPair) { return pcPair.first; });
1314 for (const auto& p : mPatches) {
1315 for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
1316 for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
1317 }
1318 for (int32_t id : portConfigIds) resetPortConfig(id);
1319}
1320
Mikhail Naganov289468a2023-03-29 10:06:15 -07001321status_t DeviceHalAidl::updateRoutes() {
1322 TIME_CHECK();
1323 std::vector<AudioRoute> routes;
1324 RETURN_STATUS_IF_ERROR(
1325 statusTFromBinderStatus(mModule->getAudioRoutes(&routes)));
1326 ALOGW_IF(routes.empty(), "%s: module %s returned an empty list of audio routes",
1327 __func__, mInstance.c_str());
1328 mRoutingMatrix.clear();
1329 for (const auto& r : routes) {
1330 for (auto portId : r.sourcePortIds) {
1331 mRoutingMatrix.emplace(r.sinkPortId, portId);
1332 mRoutingMatrix.emplace(portId, r.sinkPortId);
1333 }
1334 }
1335 return OK;
1336}
1337
Mikhail Naganovdfd594e2023-02-08 16:59:41 -08001338void DeviceHalAidl::clearCallbacks(void* cookie) {
1339 std::lock_guard l(mLock);
1340 mCallbacks.erase(cookie);
1341}
1342
1343sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1344 return getCallbackImpl(cookie, &Callbacks::out);
1345}
1346
1347void DeviceHalAidl::setStreamOutCallback(
1348 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1349 setCallbackImpl(cookie, &Callbacks::out, cb);
1350}
1351
1352sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1353 void* cookie) {
1354 return getCallbackImpl(cookie, &Callbacks::event);
1355}
1356
1357void DeviceHalAidl::setStreamOutEventCallback(
1358 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1359 setCallbackImpl(cookie, &Callbacks::event, cb);
1360}
1361
1362sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1363 void* cookie) {
1364 return getCallbackImpl(cookie, &Callbacks::latency);
1365}
1366
1367void DeviceHalAidl::setStreamOutLatencyModeCallback(
1368 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1369 setCallbackImpl(cookie, &Callbacks::latency, cb);
1370}
1371
1372template<class C>
1373sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1374 std::lock_guard l(mLock);
1375 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1376 return ((it->second).*field).promote();
1377 }
1378 return nullptr;
1379}
1380template<class C>
1381void DeviceHalAidl::setCallbackImpl(
1382 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1383 std::lock_guard l(mLock);
1384 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1385 (it->second).*field = cb;
1386 }
1387}
1388
Mikhail Naganov31d46652023-01-10 18:29:25 +00001389} // namespace android