blob: b1cdccf599810c12ab629d6335f91196fb479520 [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 Naganovfab697c2023-01-11 19:33:13 +000071using aidl::android::hardware::audio::core::IModule;
72using aidl::android::hardware::audio::core::ITelephony;
Mikhail Naganove93a0862023-03-15 17:06:59 -070073using aidl::android::hardware::audio::core::ModuleDebug;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000074using aidl::android::hardware::audio::core::StreamDescriptor;
Mikhail Naganov31d46652023-01-10 18:29:25 +000075
76namespace android {
77
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080078namespace {
79
80bool isConfigEqualToPortConfig(const AudioConfig& config, const AudioPortConfig& portConfig) {
81 return portConfig.sampleRate.value().value == config.base.sampleRate &&
82 portConfig.channelMask.value() == config.base.channelMask &&
83 portConfig.format.value() == config.base.format;
84}
85
86void setConfigFromPortConfig(AudioConfig* config, const AudioPortConfig& portConfig) {
87 config->base.sampleRate = portConfig.sampleRate.value().value;
88 config->base.channelMask = portConfig.channelMask.value();
89 config->base.format = portConfig.format.value();
90}
91
92void setPortConfigFromConfig(AudioPortConfig* portConfig, const AudioConfig& config) {
93 portConfig->sampleRate = Int{ .value = config.base.sampleRate };
94 portConfig->channelMask = config.base.channelMask;
95 portConfig->format = config.base.format;
96}
97
David Li9cf5e622023-03-21 00:51:10 +080098template<typename OutEnum, typename OutEnumRange, typename InEnum>
99ConversionResult<OutEnum> convertEnum(const OutEnumRange& range, InEnum e) {
100 using InIntType = std::underlying_type_t<InEnum>;
101 static_assert(std::is_same_v<InIntType, std::underlying_type_t<OutEnum>>);
102
103 InIntType inEnumIndex = static_cast<InIntType>(e);
104 OutEnum outEnum = static_cast<OutEnum>(inEnumIndex);
105 if (std::find(range.begin(), range.end(), outEnum) == range.end()) {
106 return ::android::base::unexpected(BAD_VALUE);
107 }
108 return outEnum;
109}
110
111template<typename NdkEnum, typename CppEnum>
112ConversionResult<NdkEnum> cpp2ndk_Enum(CppEnum e) {
113 return convertEnum<NdkEnum>(::ndk::enum_range<NdkEnum>(), e);
114}
115
116template<typename CppEnum, typename NdkEnum>
117ConversionResult<CppEnum> ndk2cpp_Enum(NdkEnum e) {
118 return convertEnum<CppEnum>(::android::enum_range<CppEnum>(), e);
119}
120
121ConversionResult<android::media::audio::common::AudioDeviceAddress>
122ndk2cpp_AudioDeviceAddress(const AudioDeviceAddress& ndk) {
123 using CppTag = android::media::audio::common::AudioDeviceAddress::Tag;
124 using NdkTag = AudioDeviceAddress::Tag;
125
126 CppTag cppTag = VALUE_OR_RETURN(ndk2cpp_Enum<CppTag>(ndk.getTag()));
127
128 switch (cppTag) {
129 case CppTag::id:
130 return android::media::audio::common::AudioDeviceAddress::make<CppTag::id>(
131 ndk.get<NdkTag::id>());
132 case CppTag::mac:
133 return android::media::audio::common::AudioDeviceAddress::make<CppTag::mac>(
134 ndk.get<NdkTag::mac>());
135 case CppTag::ipv4:
136 return android::media::audio::common::AudioDeviceAddress::make<CppTag::ipv4>(
137 ndk.get<NdkTag::ipv4>());
138 case CppTag::ipv6:
139 return android::media::audio::common::AudioDeviceAddress::make<CppTag::ipv6>(
140 ndk.get<NdkTag::ipv6>());
141 case CppTag::alsa:
142 return android::media::audio::common::AudioDeviceAddress::make<CppTag::alsa>(
143 ndk.get<NdkTag::alsa>());
144 }
145
146 return ::android::base::unexpected(BAD_VALUE);
147}
148
149ConversionResult<media::audio::common::AudioDevice> ndk2cpp_AudioDevice(const AudioDevice& ndk) {
150 media::audio::common::AudioDevice cpp;
151 cpp.type.type = VALUE_OR_RETURN(
152 ndk2cpp_Enum<media::audio::common::AudioDeviceType>(ndk.type.type));
153 cpp.type.connection = ndk.type.connection;
154 cpp.address = VALUE_OR_RETURN(ndk2cpp_AudioDeviceAddress(ndk.address));
155 return cpp;
156}
157
158ConversionResult<media::audio::common::AudioMMapPolicyInfo>
159ndk2cpp_AudioMMapPolicyInfo(const AudioMMapPolicyInfo& ndk) {
160 media::audio::common::AudioMMapPolicyInfo cpp;
161 cpp.device = VALUE_OR_RETURN(ndk2cpp_AudioDevice(ndk.device));
162 cpp.mmapPolicy = VALUE_OR_RETURN(
163 ndk2cpp_Enum<media::audio::common::AudioMMapPolicy>(ndk.mmapPolicy));
164 return cpp;
165}
166
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800167} // namespace
168
Mikhail Naganov31d46652023-01-10 18:29:25 +0000169status_t DeviceHalAidl::getSupportedDevices(uint32_t*) {
170 // Obsolete.
171 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +0000172}
173
174status_t DeviceHalAidl::initCheck() {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800175 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000176 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800177 std::vector<AudioPort> ports;
178 RETURN_STATUS_IF_ERROR(
179 statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
180 ALOGW_IF(ports.empty(), "%s: module %s returned an empty list of audio ports",
181 __func__, mInstance.c_str());
182 std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()),
183 [](const auto& p) { return std::make_pair(p.id, p); });
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800184 mDefaultInputPortId = mDefaultOutputPortId = -1;
185 const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
186 for (const auto& pair : mPorts) {
187 const auto& p = pair.second;
188 if (p.ext.getTag() == AudioPortExt::Tag::device &&
189 (p.ext.get<AudioPortExt::Tag::device>().flags & defaultDeviceFlag) != 0) {
190 if (p.flags.getTag() == AudioIoFlags::Tag::input) {
191 mDefaultInputPortId = p.id;
192 } else if (p.flags.getTag() == AudioIoFlags::Tag::output) {
193 mDefaultOutputPortId = p.id;
194 }
195 }
196 }
197 ALOGI("%s: module %s default port ids: input %d, output %d",
198 __func__, mInstance.c_str(), mDefaultInputPortId, mDefaultOutputPortId);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800199 std::vector<AudioPortConfig> portConfigs;
200 RETURN_STATUS_IF_ERROR(
201 statusTFromBinderStatus(mModule->getAudioPortConfigs(&portConfigs))); // OK if empty
202 std::transform(portConfigs.begin(), portConfigs.end(),
203 std::inserter(mPortConfigs, mPortConfigs.end()),
204 [](const auto& p) { return std::make_pair(p.id, p); });
205 std::vector<AudioPatch> patches;
206 RETURN_STATUS_IF_ERROR(
207 statusTFromBinderStatus(mModule->getAudioPatches(&patches))); // OK if empty
208 std::transform(patches.begin(), patches.end(),
209 std::inserter(mPatches, mPatches.end()),
210 [](const auto& p) { return std::make_pair(p.id, p); });
Shunkai Yao51202502022-12-12 06:11:46 +0000211 return OK;
212}
213
214status_t DeviceHalAidl::setVoiceVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000215 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000216 if (!mModule) return NO_INIT;
217 std::shared_ptr<ITelephony> telephony;
218 if (ndk::ScopedAStatus status = mModule->getTelephony(&telephony);
219 status.isOk() && telephony != nullptr) {
220 ITelephony::TelecomConfig inConfig{ .voiceVolume = Float{volume} }, outConfig;
221 RETURN_STATUS_IF_ERROR(
222 statusTFromBinderStatus(telephony->setTelecomConfig(inConfig, &outConfig)));
223 ALOGW_IF(outConfig.voiceVolume.has_value() && volume != outConfig.voiceVolume.value().value,
224 "%s: the resulting voice volume %f is not the same as requested %f",
225 __func__, outConfig.voiceVolume.value().value, volume);
226 }
227 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +0000228}
229
230status_t DeviceHalAidl::setMasterVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000231 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000232 if (!mModule) return NO_INIT;
233 return statusTFromBinderStatus(mModule->setMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000234}
235
236status_t DeviceHalAidl::getMasterVolume(float *volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000237 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000238 if (!mModule) return NO_INIT;
239 return statusTFromBinderStatus(mModule->getMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000240}
241
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000242status_t DeviceHalAidl::setMode(audio_mode_t mode) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000243 TIME_CHECK();
244 if (!mModule) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000245 AudioMode audioMode = VALUE_OR_FATAL(::aidl::android::legacy2aidl_audio_mode_t_AudioMode(mode));
246 std::shared_ptr<ITelephony> telephony;
247 if (ndk::ScopedAStatus status = mModule->getTelephony(&telephony);
248 status.isOk() && telephony != nullptr) {
249 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(telephony->switchAudioMode(audioMode)));
250 }
251 return statusTFromBinderStatus(mModule->updateAudioMode(audioMode));
Shunkai Yao51202502022-12-12 06:11:46 +0000252}
253
254status_t DeviceHalAidl::setMicMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000255 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000256 if (!mModule) return NO_INIT;
257 return statusTFromBinderStatus(mModule->setMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000258}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000259
Shunkai Yao51202502022-12-12 06:11:46 +0000260status_t DeviceHalAidl::getMicMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000261 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000262 if (!mModule) return NO_INIT;
263 return statusTFromBinderStatus(mModule->getMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000264}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000265
Shunkai Yao51202502022-12-12 06:11:46 +0000266status_t DeviceHalAidl::setMasterMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000267 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000268 if (!mModule) return NO_INIT;
269 return statusTFromBinderStatus(mModule->setMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000270}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000271
Shunkai Yao51202502022-12-12 06:11:46 +0000272status_t DeviceHalAidl::getMasterMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000273 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000274 if (!mModule) return NO_INIT;
275 return statusTFromBinderStatus(mModule->getMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000276}
277
Mikhail Naganov31d46652023-01-10 18:29:25 +0000278status_t DeviceHalAidl::setParameters(const String8& kvPairs __unused) {
279 TIME_CHECK();
280 if (!mModule) return NO_INIT;
281 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000282 return OK;
283}
284
Mikhail Naganov31d46652023-01-10 18:29:25 +0000285status_t DeviceHalAidl::getParameters(const String8& keys __unused, String8 *values) {
286 TIME_CHECK();
287 values->clear();
288 if (!mModule) return NO_INIT;
289 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000290 return OK;
291}
292
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800293namespace {
294
295class Cleanup {
296 public:
297 typedef void (DeviceHalAidl::*Cleaner)(int32_t);
298
299 Cleanup(DeviceHalAidl* device, Cleaner cleaner, int32_t id) :
300 mDevice(device), mCleaner(cleaner), mId(id) {}
301 ~Cleanup() { clean(); }
302 void clean() {
303 if (mDevice != nullptr) (mDevice->*mCleaner)(mId);
304 disarm();
305 }
306 void disarm() { mDevice = nullptr; }
307
308 private:
309 DeviceHalAidl* mDevice;
310 const Cleaner mCleaner;
311 const int32_t mId;
312};
313
314} // namespace
315
316// Since the order of container elements destruction is unspecified,
317// ensure that cleanups are performed from the most recent one and upwards.
318// This is the same as if there were individual Cleanup instances on the stack,
319// however the bonus is that we can disarm all of them with just one statement.
320class DeviceHalAidl::Cleanups : public std::forward_list<Cleanup> {
321 public:
322 ~Cleanups() { for (auto& c : *this) c.clean(); }
323 void disarmAll() { for (auto& c : *this) c.disarm(); }
324};
325
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800326status_t DeviceHalAidl::getInputBufferSize(const struct audio_config* config, size_t* size) {
327 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
328 if (size == nullptr) return BAD_VALUE;
329 TIME_CHECK();
330 if (!mModule) return NO_INIT;
331 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
332 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
333 AudioDevice aidlDevice;
334 aidlDevice.type.type = AudioDeviceType::IN_DEFAULT;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800335 AudioSource aidlSource = AudioSource::DEFAULT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800336 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
337 AudioPortConfig mixPortConfig;
338 Cleanups cleanups;
339 audio_config writableConfig = *config;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700340 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800341 RETURN_STATUS_IF_ERROR(prepareToOpenStream(0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700342 &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800343 *size = aidlConfig.frameCount *
344 getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
345 // Do not disarm cleanups to release temporary port configs.
346 return OK;
347}
348
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800349status_t DeviceHalAidl::prepareToOpenStream(
350 int32_t aidlHandle, const AudioDevice& aidlDevice, const AudioIoFlags& aidlFlags,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800351 AudioSource aidlSource, struct audio_config* config,
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800352 Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700353 AudioPatch* aidlPatch) {
354 ALOGD("%p %s::%s: handle %d, device %s, flags %s, source %s, config %s, mix port config %s",
355 this, getClassName().c_str(), __func__, aidlHandle, aidlDevice.toString().c_str(),
356 aidlFlags.toString().c_str(), toString(aidlSource).c_str(),
357 aidlConfig->toString().c_str(), mixPortConfig->toString().c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800358 const bool isInput = aidlFlags.getTag() == AudioIoFlags::Tag::input;
359 // Find / create AudioPortConfigs for the device port and the mix port,
360 // then find / create a patch between them, and open a stream on the mix port.
361 AudioPortConfig devicePortConfig;
362 bool created = false;
363 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, &devicePortConfig, &created));
364 if (created) {
365 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
366 }
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800367 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*aidlConfig, aidlFlags, aidlHandle, aidlSource,
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800368 mixPortConfig, &created));
369 if (created) {
370 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
371 }
372 setConfigFromPortConfig(aidlConfig, *mixPortConfig);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800373 if (isInput) {
374 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700375 {devicePortConfig.id}, {mixPortConfig->id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800376 } else {
377 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700378 {mixPortConfig->id}, {devicePortConfig.id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800379 }
380 if (created) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700381 cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, aidlPatch->id);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800382 }
383 if (aidlConfig->frameCount <= 0) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700384 aidlConfig->frameCount = aidlPatch->minimumStreamBufferSizeFrames;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800385 }
386 *config = VALUE_OR_RETURN_STATUS(
387 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(*aidlConfig, isInput));
388 return OK;
389}
390
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800391namespace {
392
393class StreamCallbackBase {
394 protected:
395 explicit StreamCallbackBase(const sp<CallbackBroker>& broker) : mBroker(broker) {}
396 public:
397 void* getCookie() const { return mCookie; }
398 void setCookie(void* cookie) { mCookie = cookie; }
399 sp<CallbackBroker> getBroker() const {
400 if (void* cookie = mCookie; cookie != nullptr) return mBroker.promote();
401 return nullptr;
402 }
403 private:
404 const wp<CallbackBroker> mBroker;
405 std::atomic<void*> mCookie;
406};
407
408template<class C>
409class StreamCallbackBaseHelper {
410 protected:
411 explicit StreamCallbackBaseHelper(const StreamCallbackBase& base) : mBase(base) {}
412 sp<C> getCb(const sp<CallbackBroker>& broker, void* cookie);
413 using CbRef = const sp<C>&;
414 ndk::ScopedAStatus runCb(const std::function<void(CbRef cb)>& f) {
415 if (auto cb = getCb(mBase.getBroker(), mBase.getCookie()); cb != nullptr) f(cb);
416 return ndk::ScopedAStatus::ok();
417 }
418 private:
419 const StreamCallbackBase& mBase;
420};
421
422template<>
423sp<StreamOutHalInterfaceCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>::getCb(
424 const sp<CallbackBroker>& broker, void* cookie) {
425 if (broker != nullptr) return broker->getStreamOutCallback(cookie);
426 return nullptr;
427}
428
429template<>
430sp<StreamOutHalInterfaceEventCallback>
431StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::getCb(
432 const sp<CallbackBroker>& broker, void* cookie) {
433 if (broker != nullptr) return broker->getStreamOutEventCallback(cookie);
434 return nullptr;
435}
436
437template<>
438sp<StreamOutHalInterfaceLatencyModeCallback>
439StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::getCb(
440 const sp<CallbackBroker>& broker, void* cookie) {
441 if (broker != nullptr) return broker->getStreamOutLatencyModeCallback(cookie);
442 return nullptr;
443}
444
445/*
446Note on the callback ownership.
447
448In the Binder ownership model, the server implementation is kept alive
449as long as there is any client (proxy object) alive. This is done by
450incrementing the refcount of the server-side object by the Binder framework.
451When it detects that the last client is gone, it decrements the refcount back.
452
453Thus, it is not needed to keep any references to StreamCallback on our
454side (after we have sent an instance to the client), because we are
455the server-side. The callback object will be kept alive as long as the HAL server
456holds a strong ref to IStreamCallback proxy.
457*/
458
459class OutputStreamCallbackAidl : public StreamCallbackBase,
460 public StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>,
461 public ::aidl::android::hardware::audio::core::BnStreamCallback {
462 public:
463 explicit OutputStreamCallbackAidl(const sp<CallbackBroker>& broker)
464 : StreamCallbackBase(broker),
465 StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>(
466 *static_cast<StreamCallbackBase*>(this)) {}
467 ndk::ScopedAStatus onTransferReady() override {
468 return runCb([](CbRef cb) { cb->onWriteReady(); });
469 }
470 ndk::ScopedAStatus onError() override {
471 return runCb([](CbRef cb) { cb->onError(); });
472 }
473 ndk::ScopedAStatus onDrainReady() override {
474 return runCb([](CbRef cb) { cb->onDrainReady(); });
475 }
476};
477
478class OutputStreamEventCallbackAidl :
479 public StreamCallbackBase,
480 public StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>,
481 public StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>,
482 public ::aidl::android::hardware::audio::core::BnStreamOutEventCallback {
483 public:
484 explicit OutputStreamEventCallbackAidl(const sp<CallbackBroker>& broker)
485 : StreamCallbackBase(broker),
486 StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>(
487 *static_cast<StreamCallbackBase*>(this)),
488 StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>(
489 *static_cast<StreamCallbackBase*>(this)) {}
490 ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& in_audioMetadata) override {
491 std::basic_string<uint8_t> halMetadata(in_audioMetadata.begin(), in_audioMetadata.end());
492 return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb(
493 [&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); });
494 }
495 ndk::ScopedAStatus onRecommendedLatencyModeChanged(
496 const std::vector<AudioLatencyMode>& in_modes) override {
497 auto halModes = VALUE_OR_FATAL(
498 ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
499 in_modes,
500 ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
501 return StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::runCb(
502 [&halModes](auto cb) { cb->onRecommendedLatencyModeChanged(halModes); });
503 }
504};
505
506} // namespace
507
Mikhail Naganov31d46652023-01-10 18:29:25 +0000508status_t DeviceHalAidl::openOutputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800509 audio_io_handle_t handle, audio_devices_t devices,
510 audio_output_flags_t flags, struct audio_config* config,
511 const char* address,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000512 sp<StreamOutHalInterface>* outStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800513 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000514 if (!outStream || !config) {
515 return BAD_VALUE;
516 }
517 TIME_CHECK();
518 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800519 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
520 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
521 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
522 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, false /*isInput*/));
523 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
524 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
525 int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
526 ::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
527 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
528 AudioPortConfig mixPortConfig;
529 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700530 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800531 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
532 AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700533 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800534 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
535 args.portConfigId = mixPortConfig.id;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800536 const bool isOffload = isBitPositionFlagSet(
537 aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD);
538 std::shared_ptr<OutputStreamCallbackAidl> streamCb;
539 if (isOffload) {
540 streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
541 }
542 auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
543 if (isOffload) {
544 args.offloadInfo = aidlConfig.offloadInfo;
545 args.callback = streamCb;
546 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800547 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800548 args.eventCallback = eventCb;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800549 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
550 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800551 StreamContextAidl context(ret.desc, isOffload);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800552 if (!context.isValid()) {
553 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
554 __func__, ret.desc.toString().c_str());
555 return NO_INIT;
556 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700557 *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800558 std::move(ret.stream), this /*callbackBroker*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700559 mStreams.insert(std::pair(*outStream, aidlPatch.id));
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800560 void* cbCookie = (*outStream).get();
561 {
562 std::lock_guard l(mLock);
563 mCallbacks.emplace(cbCookie, Callbacks{});
564 }
565 if (streamCb) streamCb->setCookie(cbCookie);
566 eventCb->setCookie(cbCookie);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800567 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000568 return OK;
569}
570
Mikhail Naganov31d46652023-01-10 18:29:25 +0000571status_t DeviceHalAidl::openInputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800572 audio_io_handle_t handle, audio_devices_t devices,
573 struct audio_config* config, audio_input_flags_t flags,
574 const char* address, audio_source_t source,
575 audio_devices_t outputDevice, const char* outputDeviceAddress,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000576 sp<StreamInHalInterface>* inStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800577 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000578 if (!inStream || !config) {
579 return BAD_VALUE;
580 }
581 TIME_CHECK();
582 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800583 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
584 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
585 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
586 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
587 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
588 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
589 int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
590 ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
591 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
592 AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
593 ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
594 AudioPortConfig mixPortConfig;
595 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700596 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800597 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700598 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800599 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
600 args.portConfigId = mixPortConfig.id;
601 RecordTrackMetadata aidlTrackMetadata{
602 .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
603 if (outputDevice != AUDIO_DEVICE_NONE) {
604 aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
605 ::aidl::android::legacy2aidl_audio_device_AudioDevice(
606 outputDevice, outputDeviceAddress));
607 }
608 args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
609 args.bufferSizeFrames = aidlConfig.frameCount;
610 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
611 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800612 StreamContextAidl context(ret.desc, false /*isAsynchronous*/);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800613 if (!context.isValid()) {
614 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
615 __func__, ret.desc.toString().c_str());
616 return NO_INIT;
617 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700618 *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800619 std::move(ret.stream), this /*micInfoProvider*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700620 mStreams.insert(std::pair(*inStream, aidlPatch.id));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800621 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000622 return OK;
623}
624
625status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
626 *supportsPatches = true;
627 return OK;
628}
629
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800630status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
631 const struct audio_port_config* sources,
632 unsigned int num_sinks,
633 const struct audio_port_config* sinks,
634 audio_patch_handle_t* patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800635 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000636 TIME_CHECK();
637 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800638 if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
639 sources == nullptr || sinks == nullptr || patch == nullptr) {
640 return BAD_VALUE;
641 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800642 // When the patch handle (*patch) is AUDIO_PATCH_HANDLE_NONE, it means
643 // the framework wants to create a new patch. The handle has to be generated
644 // by the HAL. Since handles generated this way can only be unique within
645 // a HAL module, the framework generates a globally unique handle, and maps
646 // it on the <HAL module, patch handle> pair.
647 // When the patch handle is set, it meant the framework intends to update
648 // an existing patch.
649 //
650 // This behavior corresponds to HAL module behavior, with the only difference
651 // that the HAL module uses `int32_t` for patch IDs. The following assert ensures
652 // that both the framework and the HAL use the same value for "no ID":
653 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
654 int32_t halPatchId = static_cast<int32_t>(*patch);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800655
656 // Upon conversion, mix port configs contain audio configuration, while
657 // device port configs contain device address. This data is used to find
658 // or create HAL configs.
659 std::vector<AudioPortConfig> aidlSources, aidlSinks;
660 for (unsigned int i = 0; i < num_sources; ++i) {
661 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
662 sources[i].role, sources[i].type)) ==
663 ::aidl::android::AudioPortDirection::INPUT;
664 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
665 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
666 sources[i], isInput, 0)));
667 }
668 for (unsigned int i = 0; i < num_sinks; ++i) {
669 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
670 sinks[i].role, sinks[i].type)) ==
671 ::aidl::android::AudioPortDirection::INPUT;
672 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
673 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
674 sinks[i], isInput, 0)));
675 }
676 Cleanups cleanups;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800677 auto existingPatchIt = halPatchId != 0 ? mPatches.find(halPatchId): mPatches.end();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800678 AudioPatch aidlPatch;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800679 if (existingPatchIt != mPatches.end()) {
680 aidlPatch = existingPatchIt->second;
681 aidlPatch.sourcePortConfigIds.clear();
682 aidlPatch.sinkPortConfigIds.clear();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800683 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800684 ALOGD("%s: sources: %s, sinks: %s",
685 __func__, ::android::internal::ToString(aidlSources).c_str(),
686 ::android::internal::ToString(aidlSinks).c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800687 auto fillPortConfigs = [&](
688 const std::vector<AudioPortConfig>& configs, std::vector<int32_t>* ids) -> status_t {
689 for (const auto& s : configs) {
690 AudioPortConfig portConfig;
691 bool created = false;
692 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(s, &portConfig, &created));
693 if (created) {
694 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, portConfig.id);
695 }
696 ids->push_back(portConfig.id);
697 }
698 return OK;
699 };
700 RETURN_STATUS_IF_ERROR(fillPortConfigs(aidlSources, &aidlPatch.sourcePortConfigIds));
701 RETURN_STATUS_IF_ERROR(fillPortConfigs(aidlSinks, &aidlPatch.sinkPortConfigIds));
702 if (existingPatchIt != mPatches.end()) {
703 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
704 mModule->setAudioPatch(aidlPatch, &aidlPatch)));
705 existingPatchIt->second = aidlPatch;
706 } else {
707 bool created = false;
708 RETURN_STATUS_IF_ERROR(findOrCreatePatch(aidlPatch, &aidlPatch, &created));
709 // Since no cleanup of the patch is needed, 'created' is ignored.
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800710 halPatchId = aidlPatch.id;
711 *patch = static_cast<audio_patch_handle_t>(halPatchId);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800712 }
713 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000714 return OK;
715}
716
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800717status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800718 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000719 TIME_CHECK();
720 if (!mModule) return NO_INIT;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800721 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
722 if (patch == AUDIO_PATCH_HANDLE_NONE) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800723 return BAD_VALUE;
724 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800725 int32_t halPatchId = static_cast<int32_t>(patch);
726 auto patchIt = mPatches.find(halPatchId);
727 if (patchIt == mPatches.end()) {
728 ALOGE("%s: patch with id %d not found", __func__, halPatchId);
729 return BAD_VALUE;
730 }
731 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->resetAudioPatch(halPatchId)));
732 mPatches.erase(patchIt);
Shunkai Yao51202502022-12-12 06:11:46 +0000733 return OK;
734}
735
Mikhail Naganove93a0862023-03-15 17:06:59 -0700736status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
737 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000738 TIME_CHECK();
739 if (!mModule) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700740 if (port == nullptr) {
741 return BAD_VALUE;
742 }
743 audio_port_v7 portV7;
744 audio_populate_audio_port_v7(port, &portV7);
745 RETURN_STATUS_IF_ERROR(getAudioPort(&portV7));
746 return audio_populate_audio_port(&portV7, port) ? OK : BAD_VALUE;
747}
748
749status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
750 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
751 TIME_CHECK();
752 if (!mModule) return NO_INIT;
753 if (port == nullptr) {
754 return BAD_VALUE;
755 }
756 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
757 ::aidl::android::AudioPortDirection::INPUT;
758 auto aidlPort = VALUE_OR_RETURN_STATUS(
759 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
760 if (aidlPort.ext.getTag() != AudioPortExt::device) {
761 ALOGE("%s: provided port is not a device port (module %s): %s",
762 __func__, mInstance.c_str(), aidlPort.toString().c_str());
763 return BAD_VALUE;
764 }
765 const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
766 // It seems that we don't have to call HAL since all valid ports have been added either
767 // during initialization, or while handling connection of an external device.
768 auto portsIt = findPort(matchDevice);
769 if (portsIt == mPorts.end()) {
770 ALOGE("%s: device port for device %s is not found in the module %s",
771 __func__, matchDevice.toString().c_str(), mInstance.c_str());
772 return BAD_VALUE;
773 }
774 const int32_t fwkId = aidlPort.id;
775 aidlPort = portsIt->second;
776 aidlPort.id = fwkId;
777 *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
778 aidlPort, isInput));
779 return OK;
780}
781
782status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
783 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
784 TIME_CHECK();
785 if (!mModule) return NO_INIT;
786 if (config == nullptr) {
787 return BAD_VALUE;
788 }
789 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
790 config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
791 AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
792 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
793 *config, isInput, 0 /*portId*/));
794 AudioPortConfig portConfig;
795 bool created = false;
796 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(requestedPortConfig, &portConfig, &created));
Shunkai Yao51202502022-12-12 06:11:46 +0000797 return OK;
798}
799
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800800MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
801 if (mMicrophones.status == Microphones::Status::UNKNOWN) {
802 TIME_CHECK();
803 std::vector<MicrophoneInfo> aidlInfo;
804 status_t status = statusTFromBinderStatus(mModule->getMicrophones(&aidlInfo));
805 if (status == OK) {
806 mMicrophones.status = Microphones::Status::QUERIED;
807 mMicrophones.info = std::move(aidlInfo);
808 } else if (status == INVALID_OPERATION) {
809 mMicrophones.status = Microphones::Status::NOT_SUPPORTED;
810 } else {
811 ALOGE("%s: Unexpected status from 'IModule.getMicrophones': %d", __func__, status);
812 return {};
813 }
814 }
815 if (mMicrophones.status == Microphones::Status::QUERIED) {
816 return &mMicrophones.info;
817 }
818 return {}; // NOT_SUPPORTED
819}
820
Shunkai Yao51202502022-12-12 06:11:46 +0000821status_t DeviceHalAidl::getMicrophones(
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800822 std::vector<audio_microphone_characteristic_t>* microphones) {
823 if (!microphones) {
824 return BAD_VALUE;
825 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000826 TIME_CHECK();
827 if (!mModule) return NO_INIT;
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800828 auto staticInfo = getMicrophoneInfo();
829 if (!staticInfo) return INVALID_OPERATION;
830 std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
831 emptyDynamicInfo.reserve(staticInfo->size());
832 std::transform(staticInfo->begin(), staticInfo->end(), std::back_inserter(emptyDynamicInfo),
833 [](const auto& info) { return MicrophoneDynamicInfo{ .id = info.id }; });
834 *microphones = VALUE_OR_RETURN_STATUS(
835 ::aidl::android::convertContainers<std::vector<audio_microphone_characteristic_t>>(
836 *staticInfo, emptyDynamicInfo,
837 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t)
838 );
Shunkai Yao51202502022-12-12 06:11:46 +0000839 return OK;
840}
841
Mikhail Naganov31d46652023-01-10 18:29:25 +0000842status_t DeviceHalAidl::addDeviceEffect(audio_port_handle_t device __unused,
843 sp<EffectHalInterface> effect) {
Shunkai Yao51202502022-12-12 06:11:46 +0000844 if (!effect) {
845 return BAD_VALUE;
846 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000847 TIME_CHECK();
848 if (!mModule) return NO_INIT;
849 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000850 return OK;
851}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000852status_t DeviceHalAidl::removeDeviceEffect(audio_port_handle_t device __unused,
Shunkai Yao51202502022-12-12 06:11:46 +0000853 sp<EffectHalInterface> effect) {
854 if (!effect) {
855 return BAD_VALUE;
856 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000857 TIME_CHECK();
858 if (!mModule) return NO_INIT;
859 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000860 return OK;
861}
862
863status_t DeviceHalAidl::getMmapPolicyInfos(
David Li9cf5e622023-03-21 00:51:10 +0800864 media::audio::common::AudioMMapPolicyType policyType,
865 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000866 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800867 AudioMMapPolicyType mmapPolicyType =
868 VALUE_OR_RETURN_STATUS(cpp2ndk_Enum<AudioMMapPolicyType>(policyType));
869
870 std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
871
872 if (status_t status = statusTFromBinderStatus(
873 mModule->getMmapPolicyInfos(mmapPolicyType, &mmapPolicyInfos)); status != OK) {
874 return status;
875 }
876
877 *policyInfos = VALUE_OR_RETURN_STATUS(
878 convertContainer<std::vector<media::audio::common::AudioMMapPolicyInfo>>(
879 mmapPolicyInfos, ndk2cpp_AudioMMapPolicyInfo));
Shunkai Yao51202502022-12-12 06:11:46 +0000880 return OK;
881}
882
883int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000884 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800885 int32_t mixerBurstCount = 0;
886 if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
887 return mixerBurstCount;
888 }
889 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000890}
891
892int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000893 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800894 int32_t hardwareBurstMinUsec = 0;
895 if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
896 return hardwareBurstMinUsec;
897 }
898 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000899}
900
901error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000902 TIME_CHECK();
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700903 if (!mModule) return NO_INIT;
904 int32_t aidlHwAvSync;
905 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
906 return VALUE_OR_RETURN_STATUS(
907 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +0000908}
909
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000910status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
911 TIME_CHECK();
912 if (!mModule) return NO_INIT;
913 return mModule->dump(fd, Args(args).args(), args.size());
David Li9cf5e622023-03-21 00:51:10 +0800914}
Shunkai Yao51202502022-12-12 06:11:46 +0000915
Mikhail Naganov31d46652023-01-10 18:29:25 +0000916int32_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports __unused) {
917 TIME_CHECK();
Shunkai Yao51202502022-12-12 06:11:46 +0000918 ALOGE("%s not implemented yet", __func__);
919 return INVALID_OPERATION;
920}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000921
Mikhail Naganove93a0862023-03-15 17:06:59 -0700922status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
923 TIME_CHECK();
924 if (!mModule) return NO_INIT;
925 if (port == nullptr) {
926 return BAD_VALUE;
927 }
928 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
929 ::aidl::android::AudioPortDirection::INPUT;
930 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
931 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
932 if (aidlPort.ext.getTag() != AudioPortExt::device) {
933 ALOGE("%s: provided port is not a device port (module %s): %s",
934 __func__, mInstance.c_str(), aidlPort.toString().c_str());
935 return BAD_VALUE;
936 }
937 if (connected) {
938 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
939 // Reset the device address to find the "template" port.
940 matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
941 auto portsIt = findPort(matchDevice);
942 if (portsIt == mPorts.end()) {
943 ALOGW("%s: device port for device %s is not found in the module %s",
944 __func__, matchDevice.toString().c_str(), mInstance.c_str());
945 return BAD_VALUE;
946 }
947 // Use the ID of the "template" port, use all the information from the provided port.
948 aidlPort.id = portsIt->first;
949 AudioPort connectedPort;
950 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
951 aidlPort, &connectedPort)));
952 const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
953 LOG_ALWAYS_FATAL_IF(!inserted,
954 "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
955 __func__, mInstance.c_str(), connectedPort.toString().c_str(),
956 it->second.toString().c_str());
957 } else { // !connected
958 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
959 auto portsIt = findPort(matchDevice);
960 if (portsIt == mPorts.end()) {
961 ALOGW("%s: device port for device %s is not found in the module %s",
962 __func__, matchDevice.toString().c_str(), mInstance.c_str());
963 return BAD_VALUE;
964 }
965 // Any streams opened on the external device must be closed by this time,
966 // thus we can clean up patches and port configs that were created for them.
967 resetUnusedPatchesAndPortConfigs();
968 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
969 portsIt->second.id)));
970 mPorts.erase(portsIt);
971 }
972 return OK;
973}
974
975status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
976 TIME_CHECK();
977 if (!mModule) return NO_INIT;
978 ModuleDebug debug{ .simulateDeviceConnections = enabled };
979 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
980 // This is important to log as it affects HAL behavior.
981 if (status == OK) {
982 ALOGI("%s: set enabled: %d", __func__, enabled);
983 } else {
984 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
985 }
986 return status;
987}
988
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800989bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
990 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
991 return p.ext.get<AudioPortExt::Tag::device>().device == device;
992}
993
994bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
995 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
996 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
997 return p.portId == mDefaultInputPortId;
998 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
999 return p.portId == mDefaultOutputPortId;
1000 }
1001 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1002}
1003
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001004status_t DeviceHalAidl::createPortConfig(
1005 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001006 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001007 AudioPortConfig appliedPortConfig;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001008 bool applied = false;
1009 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001010 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001011 if (!applied) {
1012 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001013 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001014 if (!applied) {
1015 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001016 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001017 return NO_INIT;
1018 }
1019 }
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001020 auto id = appliedPortConfig.id;
1021 auto [it, inserted] = mPortConfigs.emplace(std::move(id), std::move(appliedPortConfig));
1022 LOG_ALWAYS_FATAL_IF(!inserted, "%s: port config with id %d already exists",
1023 __func__, it->first);
1024 *result = it;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001025 return OK;
1026}
1027
1028status_t DeviceHalAidl::findOrCreatePatch(
1029 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
1030 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
1031 requestedPatch.sourcePortConfigIds.end());
1032 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
1033 requestedPatch.sinkPortConfigIds.end());
1034 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
1035}
1036
1037status_t DeviceHalAidl::findOrCreatePatch(
1038 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
1039 AudioPatch* patch, bool* created) {
1040 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
1041 if (patchIt == mPatches.end()) {
1042 TIME_CHECK();
1043 AudioPatch requestedPatch, appliedPatch;
1044 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
1045 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
1046 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
1047 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
1048 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
1049 requestedPatch, &appliedPatch)));
1050 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
1051 *created = true;
1052 } else {
1053 *created = false;
1054 }
1055 *patch = patchIt->second;
1056 return OK;
1057}
1058
1059status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device,
1060 AudioPortConfig* portConfig, bool* created) {
1061 auto portConfigIt = findPortConfig(device);
1062 if (portConfigIt == mPortConfigs.end()) {
1063 auto portsIt = findPort(device);
1064 if (portsIt == mPorts.end()) {
1065 ALOGE("%s: device port for device %s is not found in the module %s",
1066 __func__, device.toString().c_str(), mInstance.c_str());
1067 return BAD_VALUE;
1068 }
1069 AudioPortConfig requestedPortConfig;
1070 requestedPortConfig.portId = portsIt->first;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001071 RETURN_STATUS_IF_ERROR(createPortConfig(requestedPortConfig, &portConfigIt));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001072 *created = true;
1073 } else {
1074 *created = false;
1075 }
1076 *portConfig = portConfigIt->second;
1077 return OK;
1078}
1079
1080status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001081 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001082 AudioSource source, AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001083 // These flags get removed one by one in this order when retrying port finding.
1084 static const std::vector<AudioInputFlags> kOptionalInputFlags{
1085 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001086 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001087 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001088 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
1089 AudioIoFlags matchFlags = flags.value();
1090 auto portsIt = findPort(config, matchFlags);
1091 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
1092 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
1093 if (!isBitPositionFlagSet(
1094 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
1095 ++optionalInputFlagsIt;
1096 continue;
1097 }
1098 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
1099 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
1100 portsIt = findPort(config, matchFlags);
1101 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
1102 "retried with flags %s", __func__, config.toString().c_str(),
1103 flags.value().toString().c_str(), mInstance.c_str(),
1104 matchFlags.toString().c_str());
1105 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001106 if (portsIt == mPorts.end()) {
1107 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001108 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001109 mInstance.c_str());
1110 return BAD_VALUE;
1111 }
1112 AudioPortConfig requestedPortConfig;
1113 requestedPortConfig.portId = portsIt->first;
1114 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001115 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001116 if (matchFlags.getTag() == AudioIoFlags::Tag::input
1117 && source != AudioSource::SYS_RESERVED_INVALID) {
1118 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
1119 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
1120 }
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001121 RETURN_STATUS_IF_ERROR(createPortConfig(requestedPortConfig, &portConfigIt));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001122 *created = true;
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001123 } else if (!flags.has_value()) {
1124 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
1125 "and was not created as flags are not specified",
1126 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
1127 return BAD_VALUE;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001128 } else {
1129 *created = false;
1130 }
1131 *portConfig = portConfigIt->second;
1132 return OK;
1133}
1134
1135status_t DeviceHalAidl::findOrCreatePortConfig(
1136 const AudioPortConfig& requestedPortConfig, AudioPortConfig* portConfig, bool* created) {
1137 using Tag = AudioPortExt::Tag;
1138 if (requestedPortConfig.ext.getTag() == Tag::mix) {
1139 if (const auto& p = requestedPortConfig;
1140 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001141 !p.format.has_value()) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001142 ALOGW("%s: provided mix port config is not fully specified: %s",
1143 __func__, p.toString().c_str());
1144 return BAD_VALUE;
1145 }
1146 AudioConfig config;
1147 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001148 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
1149 AudioPortMixExtUseCase::Tag::source ?
1150 requestedPortConfig.ext.get<Tag::mix>().usecase.
1151 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001152 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001153 requestedPortConfig.ext.get<Tag::mix>().handle, source, portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001154 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
1155 return findOrCreatePortConfig(
1156 requestedPortConfig.ext.get<Tag::device>().device, portConfig, created);
1157 }
1158 ALOGW("%s: unsupported audio port config: %s",
1159 __func__, requestedPortConfig.toString().c_str());
1160 return BAD_VALUE;
1161}
1162
1163DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
1164 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
1165 return std::find_if(mPatches.begin(), mPatches.end(),
1166 [&](const auto& pair) {
1167 const auto& p = pair.second;
1168 std::set<int32_t> patchSrcs(
1169 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
1170 std::set<int32_t> patchSinks(
1171 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
1172 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
1173}
1174
1175DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001176 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1177 return mPorts.find(mDefaultInputPortId);
1178 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1179 return mPorts.find(mDefaultOutputPortId);
1180 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001181 return std::find_if(mPorts.begin(), mPorts.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001182 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001183}
1184
1185DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
1186 const AudioConfig& config, const AudioIoFlags& flags) {
Mikhail Naganove93a0862023-03-15 17:06:59 -07001187 auto belongsToProfile = [&config](const AudioProfile& prof) {
1188 return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
1189 (config.base.channelMask.getTag() == AudioChannelLayout::none ||
1190 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
1191 config.base.channelMask) != prof.channelMasks.end()) &&
1192 (config.base.sampleRate == 0 ||
1193 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
1194 config.base.sampleRate) != prof.sampleRates.end());
1195 };
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001196 auto matcher = [&](const auto& pair) {
1197 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001198 return p.ext.getTag() == AudioPortExt::Tag::mix &&
1199 p.flags == flags &&
Mikhail Naganove93a0862023-03-15 17:06:59 -07001200 (p.profiles.empty() ||
1201 std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
1202 p.profiles.end()); };
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001203 return std::find_if(mPorts.begin(), mPorts.end(), matcher);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001204}
1205
1206DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001207 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001208 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001209}
1210
1211DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001212 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001213 using Tag = AudioPortExt::Tag;
1214 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
1215 [&](const auto& pair) {
1216 const auto& p = pair.second;
1217 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
1218 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
1219 !p.format.has_value() || !p.flags.has_value(),
1220 "%s: stored mix port config is not fully specified: %s",
1221 __func__, p.toString().c_str());
1222 return p.ext.getTag() == Tag::mix &&
1223 isConfigEqualToPortConfig(config, p) &&
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001224 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001225 p.ext.template get<Tag::mix>().handle == ioHandle; });
1226}
Mikhail Naganove93a0862023-03-15 17:06:59 -07001227
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001228void DeviceHalAidl::resetPatch(int32_t patchId) {
1229 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1230 mPatches.erase(it);
1231 TIME_CHECK();
1232 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1233 ALOGE("%s: error while resetting patch %d: %s",
1234 __func__, patchId, status.getDescription().c_str());
1235 }
1236 return;
1237 }
1238 ALOGE("%s: patch id %d not found", __func__, patchId);
1239}
1240
1241void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1242 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1243 mPortConfigs.erase(it);
1244 TIME_CHECK();
1245 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1246 !status.isOk()) {
1247 ALOGE("%s: error while resetting port config %d: %s",
1248 __func__, portConfigId, status.getDescription().c_str());
1249 }
1250 return;
1251 }
1252 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1253}
1254
Mikhail Naganove93a0862023-03-15 17:06:59 -07001255void DeviceHalAidl::resetUnusedPatches() {
1256 // Since patches can be created independently of streams via 'createAudioPatch',
1257 // here we only clean up patches for released streams.
1258 for (auto it = mStreams.begin(); it != mStreams.end(); ) {
1259 if (auto streamSp = it->first.promote(); streamSp) {
1260 ++it;
1261 } else {
1262 resetPatch(it->second);
1263 it = mStreams.erase(it);
1264 }
1265 }
1266}
1267
1268void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
1269 resetUnusedPatches();
1270 resetUnusedPortConfigs();
1271}
1272
1273void DeviceHalAidl::resetUnusedPortConfigs() {
1274 // The assumption is that port configs are used to create patches
1275 // (or to open streams, but that involves creation of patches, too). Thus,
1276 // orphaned port configs can and should be reset.
1277 std::set<int32_t> portConfigIds;
1278 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
1279 std::inserter(portConfigIds, portConfigIds.end()),
1280 [](const auto& pcPair) { return pcPair.first; });
1281 for (const auto& p : mPatches) {
1282 for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
1283 for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
1284 }
1285 for (int32_t id : portConfigIds) resetPortConfig(id);
1286}
1287
Mikhail Naganovdfd594e2023-02-08 16:59:41 -08001288void DeviceHalAidl::clearCallbacks(void* cookie) {
1289 std::lock_guard l(mLock);
1290 mCallbacks.erase(cookie);
1291}
1292
1293sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1294 return getCallbackImpl(cookie, &Callbacks::out);
1295}
1296
1297void DeviceHalAidl::setStreamOutCallback(
1298 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1299 setCallbackImpl(cookie, &Callbacks::out, cb);
1300}
1301
1302sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1303 void* cookie) {
1304 return getCallbackImpl(cookie, &Callbacks::event);
1305}
1306
1307void DeviceHalAidl::setStreamOutEventCallback(
1308 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1309 setCallbackImpl(cookie, &Callbacks::event, cb);
1310}
1311
1312sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1313 void* cookie) {
1314 return getCallbackImpl(cookie, &Callbacks::latency);
1315}
1316
1317void DeviceHalAidl::setStreamOutLatencyModeCallback(
1318 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1319 setCallbackImpl(cookie, &Callbacks::latency, cb);
1320}
1321
1322template<class C>
1323sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1324 std::lock_guard l(mLock);
1325 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1326 return ((it->second).*field).promote();
1327 }
1328 return nullptr;
1329}
1330template<class C>
1331void DeviceHalAidl::setCallbackImpl(
1332 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1333 std::lock_guard l(mLock);
1334 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1335 (it->second).*field = cb;
1336 }
1337}
1338
Mikhail Naganov31d46652023-01-10 18:29:25 +00001339} // namespace android