blob: 1390c1653f745ea8c00132a6ed0d20882f3354f8 [file] [log] [blame]
Shunkai Yao51202502022-12-12 06:11:46 +00001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "DeviceHalAidl"
Mikhail Naganov89a9f742023-01-30 12:33:18 -080018// #define LOG_NDEBUG 0
Shunkai Yao51202502022-12-12 06:11:46 +000019
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080020#include <algorithm>
21#include <forward_list>
22
Mikhail Naganovdfd594e2023-02-08 16:59:41 -080023#include <aidl/android/hardware/audio/core/BnStreamCallback.h>
24#include <aidl/android/hardware/audio/core/BnStreamOutEventCallback.h>
Mikhail Naganovfab697c2023-01-11 19:33:13 +000025#include <aidl/android/hardware/audio/core/StreamDescriptor.h>
26#include <error/expected_utils.h>
27#include <media/AidlConversionCppNdk.h>
Mikhail Naganov25bc9a22023-04-21 18:48:16 -070028#include <media/AidlConversionNdkCpp.h>
Mikhail Naganovfab697c2023-01-11 19:33:13 +000029#include <media/AidlConversionUtil.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000030#include <mediautils/TimeCheck.h>
Mikhail Naganov89a9f742023-01-30 12:33:18 -080031#include <Utils.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000032#include <utils/Log.h>
Shunkai Yao51202502022-12-12 06:11:46 +000033
Mikhail Naganov31d46652023-01-10 18:29:25 +000034#include "DeviceHalAidl.h"
35#include "StreamHalAidl.h"
36
Mikhail Naganovfab697c2023-01-11 19:33:13 +000037using aidl::android::aidl_utils::statusTFromBinderStatus;
Mikhail Naganove93a0862023-03-15 17:06:59 -070038using aidl::android::media::audio::common::AudioChannelLayout;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080039using aidl::android::media::audio::common::AudioConfig;
40using aidl::android::media::audio::common::AudioDevice;
David Li9cf5e622023-03-21 00:51:10 +080041using aidl::android::media::audio::common::AudioDeviceAddress;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080042using aidl::android::media::audio::common::AudioDeviceType;
Mikhail Naganove93a0862023-03-15 17:06:59 -070043using aidl::android::media::audio::common::AudioFormatType;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080044using aidl::android::media::audio::common::AudioInputFlags;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080045using aidl::android::media::audio::common::AudioIoFlags;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -080046using aidl::android::media::audio::common::AudioLatencyMode;
David Li9cf5e622023-03-21 00:51:10 +080047using aidl::android::media::audio::common::AudioMMapPolicy;
48using aidl::android::media::audio::common::AudioMMapPolicyInfo;
49using aidl::android::media::audio::common::AudioMMapPolicyType;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000050using aidl::android::media::audio::common::AudioMode;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080051using aidl::android::media::audio::common::AudioOutputFlags;
52using aidl::android::media::audio::common::AudioPort;
53using aidl::android::media::audio::common::AudioPortConfig;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080054using aidl::android::media::audio::common::AudioPortDeviceExt;
David Li9cf5e622023-03-21 00:51:10 +080055using aidl::android::media::audio::common::AudioPortExt;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -080056using aidl::android::media::audio::common::AudioPortMixExt;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -080057using aidl::android::media::audio::common::AudioPortMixExtUseCase;
Mikhail Naganove93a0862023-03-15 17:06:59 -070058using aidl::android::media::audio::common::AudioProfile;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080059using aidl::android::media::audio::common::AudioSource;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000060using aidl::android::media::audio::common::Float;
David Li9cf5e622023-03-21 00:51:10 +080061using aidl::android::media::audio::common::Int;
62using aidl::android::media::audio::common::MicrophoneDynamicInfo;
63using aidl::android::media::audio::common::MicrophoneInfo;
Mikhail Naganov6352e822023-03-09 18:22:36 -080064using aidl::android::hardware::audio::common::getFrameSizeInBytes;
65using aidl::android::hardware::audio::common::isBitPositionFlagSet;
Mikhail Naganove93a0862023-03-15 17:06:59 -070066using aidl::android::hardware::audio::common::isDefaultAudioFormat;
Mikhail Naganov6352e822023-03-09 18:22:36 -080067using aidl::android::hardware::audio::common::makeBitPositionFlagMask;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080068using aidl::android::hardware::audio::common::RecordTrackMetadata;
69using aidl::android::hardware::audio::core::AudioPatch;
Mikhail Naganov289468a2023-03-29 10:06:15 -070070using aidl::android::hardware::audio::core::AudioRoute;
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
Mikhail Naganovf83b9742023-04-24 13:06:04 -070098// Note: these converters are for types defined in different AIDL files. Although these
99// AIDL files are copies of each other, however formally these are different types
100// thus we don't use a conversion via a parcelable.
101ConversionResult<media::AudioRoute> ndk2cpp_AudioRoute(const AudioRoute& ndk) {
102 media::AudioRoute cpp;
103 cpp.sourcePortIds.insert(
104 cpp.sourcePortIds.end(), ndk.sourcePortIds.begin(), ndk.sourcePortIds.end());
105 cpp.sinkPortId = ndk.sinkPortId;
106 cpp.isExclusive = ndk.isExclusive;
David Li9cf5e622023-03-21 00:51:10 +0800107 return cpp;
108}
109
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800110} // namespace
111
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700112status_t DeviceHalAidl::getAudioPorts(std::vector<media::audio::common::AudioPort> *ports) {
113 auto convertAudioPortFromMap = [](const Ports::value_type& pair) {
114 return ndk2cpp_AudioPort(pair.second);
115 };
116 return ::aidl::android::convertRange(mPorts.begin(), mPorts.end(), ports->begin(),
117 convertAudioPortFromMap);
118}
119
120status_t DeviceHalAidl::getAudioRoutes(std::vector<media::AudioRoute> *routes) {
121 *routes = VALUE_OR_RETURN_STATUS(
122 ::aidl::android::convertContainer<std::vector<media::AudioRoute>>(
123 mRoutes, ndk2cpp_AudioRoute));
124 return OK;
125}
126
Mikhail Naganov31d46652023-01-10 18:29:25 +0000127status_t DeviceHalAidl::getSupportedDevices(uint32_t*) {
128 // Obsolete.
129 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +0000130}
131
132status_t DeviceHalAidl::initCheck() {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800133 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000134 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800135 std::vector<AudioPort> ports;
Mikhail Naganovf83b9742023-04-24 13:06:04 -0700136 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800137 ALOGW_IF(ports.empty(), "%s: module %s returned an empty list of audio ports",
138 __func__, mInstance.c_str());
139 std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()),
140 [](const auto& p) { return std::make_pair(p.id, p); });
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800141 mDefaultInputPortId = mDefaultOutputPortId = -1;
142 const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
143 for (const auto& pair : mPorts) {
144 const auto& p = pair.second;
145 if (p.ext.getTag() == AudioPortExt::Tag::device &&
146 (p.ext.get<AudioPortExt::Tag::device>().flags & defaultDeviceFlag) != 0) {
147 if (p.flags.getTag() == AudioIoFlags::Tag::input) {
148 mDefaultInputPortId = p.id;
149 } else if (p.flags.getTag() == AudioIoFlags::Tag::output) {
150 mDefaultOutputPortId = p.id;
151 }
152 }
153 }
154 ALOGI("%s: module %s default port ids: input %d, output %d",
155 __func__, mInstance.c_str(), mDefaultInputPortId, mDefaultOutputPortId);
Mikhail Naganov289468a2023-03-29 10:06:15 -0700156 RETURN_STATUS_IF_ERROR(updateRoutes());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800157 std::vector<AudioPortConfig> portConfigs;
158 RETURN_STATUS_IF_ERROR(
159 statusTFromBinderStatus(mModule->getAudioPortConfigs(&portConfigs))); // OK if empty
160 std::transform(portConfigs.begin(), portConfigs.end(),
161 std::inserter(mPortConfigs, mPortConfigs.end()),
162 [](const auto& p) { return std::make_pair(p.id, p); });
jiabin9c07faf2023-04-26 22:00:44 +0000163 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
164 std::inserter(mInitialPortConfigIds, mInitialPortConfigIds.end()),
165 [](const auto& pcPair) { return pcPair.first; });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800166 std::vector<AudioPatch> patches;
167 RETURN_STATUS_IF_ERROR(
168 statusTFromBinderStatus(mModule->getAudioPatches(&patches))); // OK if empty
169 std::transform(patches.begin(), patches.end(),
170 std::inserter(mPatches, mPatches.end()),
171 [](const auto& p) { return std::make_pair(p.id, p); });
Shunkai Yao51202502022-12-12 06:11:46 +0000172 return OK;
173}
174
175status_t DeviceHalAidl::setVoiceVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000176 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000177 if (!mModule) return NO_INIT;
178 std::shared_ptr<ITelephony> telephony;
179 if (ndk::ScopedAStatus status = mModule->getTelephony(&telephony);
180 status.isOk() && telephony != nullptr) {
181 ITelephony::TelecomConfig inConfig{ .voiceVolume = Float{volume} }, outConfig;
182 RETURN_STATUS_IF_ERROR(
183 statusTFromBinderStatus(telephony->setTelecomConfig(inConfig, &outConfig)));
184 ALOGW_IF(outConfig.voiceVolume.has_value() && volume != outConfig.voiceVolume.value().value,
185 "%s: the resulting voice volume %f is not the same as requested %f",
186 __func__, outConfig.voiceVolume.value().value, volume);
187 }
188 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +0000189}
190
191status_t DeviceHalAidl::setMasterVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000192 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000193 if (!mModule) return NO_INIT;
194 return statusTFromBinderStatus(mModule->setMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000195}
196
197status_t DeviceHalAidl::getMasterVolume(float *volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000198 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000199 if (!mModule) return NO_INIT;
200 return statusTFromBinderStatus(mModule->getMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000201}
202
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000203status_t DeviceHalAidl::setMode(audio_mode_t mode) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000204 TIME_CHECK();
205 if (!mModule) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000206 AudioMode audioMode = VALUE_OR_FATAL(::aidl::android::legacy2aidl_audio_mode_t_AudioMode(mode));
207 std::shared_ptr<ITelephony> telephony;
208 if (ndk::ScopedAStatus status = mModule->getTelephony(&telephony);
209 status.isOk() && telephony != nullptr) {
210 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(telephony->switchAudioMode(audioMode)));
211 }
212 return statusTFromBinderStatus(mModule->updateAudioMode(audioMode));
Shunkai Yao51202502022-12-12 06:11:46 +0000213}
214
215status_t DeviceHalAidl::setMicMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000216 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000217 if (!mModule) return NO_INIT;
218 return statusTFromBinderStatus(mModule->setMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000219}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000220
Shunkai Yao51202502022-12-12 06:11:46 +0000221status_t DeviceHalAidl::getMicMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000222 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000223 if (!mModule) return NO_INIT;
224 return statusTFromBinderStatus(mModule->getMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000225}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000226
Shunkai Yao51202502022-12-12 06:11:46 +0000227status_t DeviceHalAidl::setMasterMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000228 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000229 if (!mModule) return NO_INIT;
230 return statusTFromBinderStatus(mModule->setMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000231}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000232
Shunkai Yao51202502022-12-12 06:11:46 +0000233status_t DeviceHalAidl::getMasterMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000234 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000235 if (!mModule) return NO_INIT;
236 return statusTFromBinderStatus(mModule->getMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000237}
238
Mikhail Naganov31d46652023-01-10 18:29:25 +0000239status_t DeviceHalAidl::setParameters(const String8& kvPairs __unused) {
240 TIME_CHECK();
241 if (!mModule) return NO_INIT;
242 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000243 return OK;
244}
245
Mikhail Naganov31d46652023-01-10 18:29:25 +0000246status_t DeviceHalAidl::getParameters(const String8& keys __unused, String8 *values) {
247 TIME_CHECK();
248 values->clear();
249 if (!mModule) return NO_INIT;
250 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000251 return OK;
252}
253
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800254namespace {
255
256class Cleanup {
257 public:
258 typedef void (DeviceHalAidl::*Cleaner)(int32_t);
259
260 Cleanup(DeviceHalAidl* device, Cleaner cleaner, int32_t id) :
261 mDevice(device), mCleaner(cleaner), mId(id) {}
262 ~Cleanup() { clean(); }
263 void clean() {
264 if (mDevice != nullptr) (mDevice->*mCleaner)(mId);
265 disarm();
266 }
267 void disarm() { mDevice = nullptr; }
268
269 private:
270 DeviceHalAidl* mDevice;
271 const Cleaner mCleaner;
272 const int32_t mId;
273};
274
275} // namespace
276
277// Since the order of container elements destruction is unspecified,
278// ensure that cleanups are performed from the most recent one and upwards.
279// This is the same as if there were individual Cleanup instances on the stack,
280// however the bonus is that we can disarm all of them with just one statement.
281class DeviceHalAidl::Cleanups : public std::forward_list<Cleanup> {
282 public:
283 ~Cleanups() { for (auto& c : *this) c.clean(); }
284 void disarmAll() { for (auto& c : *this) c.disarm(); }
285};
286
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800287status_t DeviceHalAidl::getInputBufferSize(const struct audio_config* config, size_t* size) {
288 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
289 if (size == nullptr) return BAD_VALUE;
290 TIME_CHECK();
291 if (!mModule) return NO_INIT;
292 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
293 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
294 AudioDevice aidlDevice;
295 aidlDevice.type.type = AudioDeviceType::IN_DEFAULT;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800296 AudioSource aidlSource = AudioSource::DEFAULT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800297 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
298 AudioPortConfig mixPortConfig;
299 Cleanups cleanups;
300 audio_config writableConfig = *config;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700301 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800302 RETURN_STATUS_IF_ERROR(prepareToOpenStream(0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700303 &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800304 *size = aidlConfig.frameCount *
305 getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
306 // Do not disarm cleanups to release temporary port configs.
307 return OK;
308}
309
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800310status_t DeviceHalAidl::prepareToOpenStream(
311 int32_t aidlHandle, const AudioDevice& aidlDevice, const AudioIoFlags& aidlFlags,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800312 AudioSource aidlSource, struct audio_config* config,
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800313 Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700314 AudioPatch* aidlPatch) {
315 ALOGD("%p %s::%s: handle %d, device %s, flags %s, source %s, config %s, mix port config %s",
316 this, getClassName().c_str(), __func__, aidlHandle, aidlDevice.toString().c_str(),
317 aidlFlags.toString().c_str(), toString(aidlSource).c_str(),
318 aidlConfig->toString().c_str(), mixPortConfig->toString().c_str());
jiabin9c07faf2023-04-26 22:00:44 +0000319 resetUnusedPatchesAndPortConfigs();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800320 const bool isInput = aidlFlags.getTag() == AudioIoFlags::Tag::input;
321 // Find / create AudioPortConfigs for the device port and the mix port,
322 // then find / create a patch between them, and open a stream on the mix port.
323 AudioPortConfig devicePortConfig;
324 bool created = false;
jiabin9c07faf2023-04-26 22:00:44 +0000325 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, aidlConfig,
326 &devicePortConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800327 if (created) {
328 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
329 }
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800330 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*aidlConfig, aidlFlags, aidlHandle, aidlSource,
Mikhail Naganov289468a2023-03-29 10:06:15 -0700331 std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800332 if (created) {
333 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
334 }
335 setConfigFromPortConfig(aidlConfig, *mixPortConfig);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800336 if (isInput) {
337 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700338 {devicePortConfig.id}, {mixPortConfig->id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800339 } else {
340 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700341 {mixPortConfig->id}, {devicePortConfig.id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800342 }
343 if (created) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700344 cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, aidlPatch->id);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800345 }
346 if (aidlConfig->frameCount <= 0) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700347 aidlConfig->frameCount = aidlPatch->minimumStreamBufferSizeFrames;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800348 }
349 *config = VALUE_OR_RETURN_STATUS(
350 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(*aidlConfig, isInput));
351 return OK;
352}
353
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800354namespace {
355
356class StreamCallbackBase {
357 protected:
358 explicit StreamCallbackBase(const sp<CallbackBroker>& broker) : mBroker(broker) {}
359 public:
360 void* getCookie() const { return mCookie; }
361 void setCookie(void* cookie) { mCookie = cookie; }
362 sp<CallbackBroker> getBroker() const {
363 if (void* cookie = mCookie; cookie != nullptr) return mBroker.promote();
364 return nullptr;
365 }
366 private:
367 const wp<CallbackBroker> mBroker;
368 std::atomic<void*> mCookie;
369};
370
371template<class C>
372class StreamCallbackBaseHelper {
373 protected:
374 explicit StreamCallbackBaseHelper(const StreamCallbackBase& base) : mBase(base) {}
375 sp<C> getCb(const sp<CallbackBroker>& broker, void* cookie);
376 using CbRef = const sp<C>&;
377 ndk::ScopedAStatus runCb(const std::function<void(CbRef cb)>& f) {
378 if (auto cb = getCb(mBase.getBroker(), mBase.getCookie()); cb != nullptr) f(cb);
379 return ndk::ScopedAStatus::ok();
380 }
381 private:
382 const StreamCallbackBase& mBase;
383};
384
385template<>
386sp<StreamOutHalInterfaceCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>::getCb(
387 const sp<CallbackBroker>& broker, void* cookie) {
388 if (broker != nullptr) return broker->getStreamOutCallback(cookie);
389 return nullptr;
390}
391
392template<>
393sp<StreamOutHalInterfaceEventCallback>
394StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::getCb(
395 const sp<CallbackBroker>& broker, void* cookie) {
396 if (broker != nullptr) return broker->getStreamOutEventCallback(cookie);
397 return nullptr;
398}
399
400template<>
401sp<StreamOutHalInterfaceLatencyModeCallback>
402StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::getCb(
403 const sp<CallbackBroker>& broker, void* cookie) {
404 if (broker != nullptr) return broker->getStreamOutLatencyModeCallback(cookie);
405 return nullptr;
406}
407
408/*
409Note on the callback ownership.
410
411In the Binder ownership model, the server implementation is kept alive
412as long as there is any client (proxy object) alive. This is done by
413incrementing the refcount of the server-side object by the Binder framework.
414When it detects that the last client is gone, it decrements the refcount back.
415
416Thus, it is not needed to keep any references to StreamCallback on our
417side (after we have sent an instance to the client), because we are
418the server-side. The callback object will be kept alive as long as the HAL server
419holds a strong ref to IStreamCallback proxy.
420*/
421
422class OutputStreamCallbackAidl : public StreamCallbackBase,
423 public StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>,
424 public ::aidl::android::hardware::audio::core::BnStreamCallback {
425 public:
426 explicit OutputStreamCallbackAidl(const sp<CallbackBroker>& broker)
427 : StreamCallbackBase(broker),
428 StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>(
429 *static_cast<StreamCallbackBase*>(this)) {}
430 ndk::ScopedAStatus onTransferReady() override {
431 return runCb([](CbRef cb) { cb->onWriteReady(); });
432 }
433 ndk::ScopedAStatus onError() override {
434 return runCb([](CbRef cb) { cb->onError(); });
435 }
436 ndk::ScopedAStatus onDrainReady() override {
437 return runCb([](CbRef cb) { cb->onDrainReady(); });
438 }
439};
440
441class OutputStreamEventCallbackAidl :
442 public StreamCallbackBase,
443 public StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>,
444 public StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>,
445 public ::aidl::android::hardware::audio::core::BnStreamOutEventCallback {
446 public:
447 explicit OutputStreamEventCallbackAidl(const sp<CallbackBroker>& broker)
448 : StreamCallbackBase(broker),
449 StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>(
450 *static_cast<StreamCallbackBase*>(this)),
451 StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>(
452 *static_cast<StreamCallbackBase*>(this)) {}
453 ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& in_audioMetadata) override {
454 std::basic_string<uint8_t> halMetadata(in_audioMetadata.begin(), in_audioMetadata.end());
455 return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb(
456 [&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); });
457 }
458 ndk::ScopedAStatus onRecommendedLatencyModeChanged(
459 const std::vector<AudioLatencyMode>& in_modes) override {
460 auto halModes = VALUE_OR_FATAL(
461 ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
462 in_modes,
463 ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
464 return StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::runCb(
465 [&halModes](auto cb) { cb->onRecommendedLatencyModeChanged(halModes); });
466 }
467};
468
469} // namespace
470
Mikhail Naganov31d46652023-01-10 18:29:25 +0000471status_t DeviceHalAidl::openOutputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800472 audio_io_handle_t handle, audio_devices_t devices,
473 audio_output_flags_t flags, struct audio_config* config,
474 const char* address,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000475 sp<StreamOutHalInterface>* outStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800476 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000477 if (!outStream || !config) {
478 return BAD_VALUE;
479 }
480 TIME_CHECK();
481 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800482 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
483 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
484 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
485 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, false /*isInput*/));
486 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
487 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
488 int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
489 ::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
490 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
491 AudioPortConfig mixPortConfig;
492 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700493 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800494 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
495 AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700496 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800497 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
498 args.portConfigId = mixPortConfig.id;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800499 const bool isOffload = isBitPositionFlagSet(
500 aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD);
501 std::shared_ptr<OutputStreamCallbackAidl> streamCb;
502 if (isOffload) {
503 streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
504 }
505 auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
506 if (isOffload) {
507 args.offloadInfo = aidlConfig.offloadInfo;
508 args.callback = streamCb;
509 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800510 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800511 args.eventCallback = eventCb;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800512 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
513 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800514 StreamContextAidl context(ret.desc, isOffload);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800515 if (!context.isValid()) {
516 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
517 __func__, ret.desc.toString().c_str());
518 return NO_INIT;
519 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700520 *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800521 std::move(ret.stream), this /*callbackBroker*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700522 mStreams.insert(std::pair(*outStream, aidlPatch.id));
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800523 void* cbCookie = (*outStream).get();
524 {
525 std::lock_guard l(mLock);
526 mCallbacks.emplace(cbCookie, Callbacks{});
527 }
528 if (streamCb) streamCb->setCookie(cbCookie);
529 eventCb->setCookie(cbCookie);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800530 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000531 return OK;
532}
533
Mikhail Naganov31d46652023-01-10 18:29:25 +0000534status_t DeviceHalAidl::openInputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800535 audio_io_handle_t handle, audio_devices_t devices,
536 struct audio_config* config, audio_input_flags_t flags,
537 const char* address, audio_source_t source,
538 audio_devices_t outputDevice, const char* outputDeviceAddress,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000539 sp<StreamInHalInterface>* inStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800540 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000541 if (!inStream || !config) {
542 return BAD_VALUE;
543 }
544 TIME_CHECK();
545 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800546 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
547 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
548 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
549 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
550 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
551 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
552 int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
553 ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
554 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
555 AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
556 ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
557 AudioPortConfig mixPortConfig;
558 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700559 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800560 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700561 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800562 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
563 args.portConfigId = mixPortConfig.id;
564 RecordTrackMetadata aidlTrackMetadata{
565 .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
566 if (outputDevice != AUDIO_DEVICE_NONE) {
567 aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
568 ::aidl::android::legacy2aidl_audio_device_AudioDevice(
569 outputDevice, outputDeviceAddress));
570 }
571 args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
572 args.bufferSizeFrames = aidlConfig.frameCount;
573 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
574 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800575 StreamContextAidl context(ret.desc, false /*isAsynchronous*/);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800576 if (!context.isValid()) {
577 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
578 __func__, ret.desc.toString().c_str());
579 return NO_INIT;
580 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700581 *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800582 std::move(ret.stream), this /*micInfoProvider*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700583 mStreams.insert(std::pair(*inStream, aidlPatch.id));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800584 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000585 return OK;
586}
587
588status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
589 *supportsPatches = true;
590 return OK;
591}
592
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800593status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
594 const struct audio_port_config* sources,
595 unsigned int num_sinks,
596 const struct audio_port_config* sinks,
597 audio_patch_handle_t* patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800598 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000599 TIME_CHECK();
600 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800601 if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
602 sources == nullptr || sinks == nullptr || patch == nullptr) {
603 return BAD_VALUE;
604 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800605 // When the patch handle (*patch) is AUDIO_PATCH_HANDLE_NONE, it means
606 // the framework wants to create a new patch. The handle has to be generated
607 // by the HAL. Since handles generated this way can only be unique within
608 // a HAL module, the framework generates a globally unique handle, and maps
609 // it on the <HAL module, patch handle> pair.
610 // When the patch handle is set, it meant the framework intends to update
611 // an existing patch.
612 //
613 // This behavior corresponds to HAL module behavior, with the only difference
614 // that the HAL module uses `int32_t` for patch IDs. The following assert ensures
615 // that both the framework and the HAL use the same value for "no ID":
616 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
617 int32_t halPatchId = static_cast<int32_t>(*patch);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800618
619 // Upon conversion, mix port configs contain audio configuration, while
620 // device port configs contain device address. This data is used to find
621 // or create HAL configs.
622 std::vector<AudioPortConfig> aidlSources, aidlSinks;
623 for (unsigned int i = 0; i < num_sources; ++i) {
624 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
625 sources[i].role, sources[i].type)) ==
626 ::aidl::android::AudioPortDirection::INPUT;
627 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
628 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
629 sources[i], isInput, 0)));
630 }
631 for (unsigned int i = 0; i < num_sinks; ++i) {
632 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
633 sinks[i].role, sinks[i].type)) ==
634 ::aidl::android::AudioPortDirection::INPUT;
635 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
636 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
637 sinks[i], isInput, 0)));
638 }
639 Cleanups cleanups;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800640 auto existingPatchIt = halPatchId != 0 ? mPatches.find(halPatchId): mPatches.end();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800641 AudioPatch aidlPatch;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800642 if (existingPatchIt != mPatches.end()) {
643 aidlPatch = existingPatchIt->second;
644 aidlPatch.sourcePortConfigIds.clear();
645 aidlPatch.sinkPortConfigIds.clear();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800646 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800647 ALOGD("%s: sources: %s, sinks: %s",
648 __func__, ::android::internal::ToString(aidlSources).c_str(),
649 ::android::internal::ToString(aidlSinks).c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800650 auto fillPortConfigs = [&](
Mikhail Naganov289468a2023-03-29 10:06:15 -0700651 const std::vector<AudioPortConfig>& configs,
652 const std::set<int32_t>& destinationPortIds,
653 std::vector<int32_t>* ids, std::set<int32_t>* portIds) -> status_t {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800654 for (const auto& s : configs) {
655 AudioPortConfig portConfig;
656 bool created = false;
Mikhail Naganov289468a2023-03-29 10:06:15 -0700657 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
658 s, destinationPortIds, &portConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800659 if (created) {
660 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, portConfig.id);
661 }
662 ids->push_back(portConfig.id);
Mikhail Naganov289468a2023-03-29 10:06:15 -0700663 if (portIds != nullptr) {
664 portIds->insert(portConfig.portId);
665 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800666 }
667 return OK;
668 };
Mikhail Naganov289468a2023-03-29 10:06:15 -0700669 // When looking up port configs, the destinationPortId is only used for mix ports.
670 // Thus, we process device port configs first, and look up the destination port ID from them.
671 bool sourceIsDevice = std::any_of(aidlSources.begin(), aidlSources.end(),
672 [](const auto& config) { return config.ext.getTag() == AudioPortExt::device; });
673 const std::vector<AudioPortConfig>& devicePortConfigs =
674 sourceIsDevice ? aidlSources : aidlSinks;
675 std::vector<int32_t>* devicePortConfigIds =
676 sourceIsDevice ? &aidlPatch.sourcePortConfigIds : &aidlPatch.sinkPortConfigIds;
677 const std::vector<AudioPortConfig>& mixPortConfigs =
678 sourceIsDevice ? aidlSinks : aidlSources;
679 std::vector<int32_t>* mixPortConfigIds =
680 sourceIsDevice ? &aidlPatch.sinkPortConfigIds : &aidlPatch.sourcePortConfigIds;
681 std::set<int32_t> devicePortIds;
682 RETURN_STATUS_IF_ERROR(fillPortConfigs(
683 devicePortConfigs, std::set<int32_t>(), devicePortConfigIds, &devicePortIds));
684 RETURN_STATUS_IF_ERROR(fillPortConfigs(
685 mixPortConfigs, devicePortIds, mixPortConfigIds, nullptr));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800686 if (existingPatchIt != mPatches.end()) {
687 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
688 mModule->setAudioPatch(aidlPatch, &aidlPatch)));
689 existingPatchIt->second = aidlPatch;
690 } else {
691 bool created = false;
692 RETURN_STATUS_IF_ERROR(findOrCreatePatch(aidlPatch, &aidlPatch, &created));
693 // Since no cleanup of the patch is needed, 'created' is ignored.
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800694 halPatchId = aidlPatch.id;
695 *patch = static_cast<audio_patch_handle_t>(halPatchId);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800696 }
697 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000698 return OK;
699}
700
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800701status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800702 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000703 TIME_CHECK();
704 if (!mModule) return NO_INIT;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800705 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
706 if (patch == AUDIO_PATCH_HANDLE_NONE) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800707 return BAD_VALUE;
708 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800709 int32_t halPatchId = static_cast<int32_t>(patch);
710 auto patchIt = mPatches.find(halPatchId);
711 if (patchIt == mPatches.end()) {
712 ALOGE("%s: patch with id %d not found", __func__, halPatchId);
713 return BAD_VALUE;
714 }
715 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->resetAudioPatch(halPatchId)));
716 mPatches.erase(patchIt);
Shunkai Yao51202502022-12-12 06:11:46 +0000717 return OK;
718}
719
Mikhail Naganove93a0862023-03-15 17:06:59 -0700720status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
721 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000722 TIME_CHECK();
723 if (!mModule) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700724 if (port == nullptr) {
725 return BAD_VALUE;
726 }
727 audio_port_v7 portV7;
728 audio_populate_audio_port_v7(port, &portV7);
729 RETURN_STATUS_IF_ERROR(getAudioPort(&portV7));
730 return audio_populate_audio_port(&portV7, port) ? OK : BAD_VALUE;
731}
732
733status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
734 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
735 TIME_CHECK();
736 if (!mModule) return NO_INIT;
737 if (port == nullptr) {
738 return BAD_VALUE;
739 }
740 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
741 ::aidl::android::AudioPortDirection::INPUT;
742 auto aidlPort = VALUE_OR_RETURN_STATUS(
743 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
744 if (aidlPort.ext.getTag() != AudioPortExt::device) {
745 ALOGE("%s: provided port is not a device port (module %s): %s",
746 __func__, mInstance.c_str(), aidlPort.toString().c_str());
747 return BAD_VALUE;
748 }
749 const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
750 // It seems that we don't have to call HAL since all valid ports have been added either
751 // during initialization, or while handling connection of an external device.
752 auto portsIt = findPort(matchDevice);
753 if (portsIt == mPorts.end()) {
754 ALOGE("%s: device port for device %s is not found in the module %s",
755 __func__, matchDevice.toString().c_str(), mInstance.c_str());
756 return BAD_VALUE;
757 }
758 const int32_t fwkId = aidlPort.id;
759 aidlPort = portsIt->second;
760 aidlPort.id = fwkId;
761 *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
762 aidlPort, isInput));
763 return OK;
764}
765
766status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
767 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
768 TIME_CHECK();
769 if (!mModule) return NO_INIT;
770 if (config == nullptr) {
771 return BAD_VALUE;
772 }
773 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
774 config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
775 AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
776 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
777 *config, isInput, 0 /*portId*/));
778 AudioPortConfig portConfig;
779 bool created = false;
Mikhail Naganov289468a2023-03-29 10:06:15 -0700780 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
781 requestedPortConfig, std::set<int32_t>(), &portConfig, &created));
Shunkai Yao51202502022-12-12 06:11:46 +0000782 return OK;
783}
784
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800785MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
786 if (mMicrophones.status == Microphones::Status::UNKNOWN) {
787 TIME_CHECK();
788 std::vector<MicrophoneInfo> aidlInfo;
789 status_t status = statusTFromBinderStatus(mModule->getMicrophones(&aidlInfo));
790 if (status == OK) {
791 mMicrophones.status = Microphones::Status::QUERIED;
792 mMicrophones.info = std::move(aidlInfo);
793 } else if (status == INVALID_OPERATION) {
794 mMicrophones.status = Microphones::Status::NOT_SUPPORTED;
795 } else {
796 ALOGE("%s: Unexpected status from 'IModule.getMicrophones': %d", __func__, status);
797 return {};
798 }
799 }
800 if (mMicrophones.status == Microphones::Status::QUERIED) {
801 return &mMicrophones.info;
802 }
803 return {}; // NOT_SUPPORTED
804}
805
Shunkai Yao51202502022-12-12 06:11:46 +0000806status_t DeviceHalAidl::getMicrophones(
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800807 std::vector<audio_microphone_characteristic_t>* microphones) {
808 if (!microphones) {
809 return BAD_VALUE;
810 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000811 TIME_CHECK();
812 if (!mModule) return NO_INIT;
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800813 auto staticInfo = getMicrophoneInfo();
814 if (!staticInfo) return INVALID_OPERATION;
815 std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
816 emptyDynamicInfo.reserve(staticInfo->size());
817 std::transform(staticInfo->begin(), staticInfo->end(), std::back_inserter(emptyDynamicInfo),
818 [](const auto& info) { return MicrophoneDynamicInfo{ .id = info.id }; });
819 *microphones = VALUE_OR_RETURN_STATUS(
820 ::aidl::android::convertContainers<std::vector<audio_microphone_characteristic_t>>(
821 *staticInfo, emptyDynamicInfo,
822 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t)
823 );
Shunkai Yao51202502022-12-12 06:11:46 +0000824 return OK;
825}
826
Mikhail Naganov31d46652023-01-10 18:29:25 +0000827status_t DeviceHalAidl::addDeviceEffect(audio_port_handle_t device __unused,
828 sp<EffectHalInterface> effect) {
Shunkai Yao51202502022-12-12 06:11:46 +0000829 if (!effect) {
830 return BAD_VALUE;
831 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000832 TIME_CHECK();
833 if (!mModule) return NO_INIT;
834 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000835 return OK;
836}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000837status_t DeviceHalAidl::removeDeviceEffect(audio_port_handle_t device __unused,
Shunkai Yao51202502022-12-12 06:11:46 +0000838 sp<EffectHalInterface> effect) {
839 if (!effect) {
840 return BAD_VALUE;
841 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000842 TIME_CHECK();
843 if (!mModule) return NO_INIT;
844 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000845 return OK;
846}
847
848status_t DeviceHalAidl::getMmapPolicyInfos(
David Li9cf5e622023-03-21 00:51:10 +0800849 media::audio::common::AudioMMapPolicyType policyType,
850 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000851 TIME_CHECK();
Mikhail Naganov25bc9a22023-04-21 18:48:16 -0700852 AudioMMapPolicyType mmapPolicyType = VALUE_OR_RETURN_STATUS(
853 cpp2ndk_AudioMMapPolicyType(policyType));
David Li9cf5e622023-03-21 00:51:10 +0800854
855 std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
856
857 if (status_t status = statusTFromBinderStatus(
858 mModule->getMmapPolicyInfos(mmapPolicyType, &mmapPolicyInfos)); status != OK) {
859 return status;
860 }
861
862 *policyInfos = VALUE_OR_RETURN_STATUS(
863 convertContainer<std::vector<media::audio::common::AudioMMapPolicyInfo>>(
864 mmapPolicyInfos, ndk2cpp_AudioMMapPolicyInfo));
Shunkai Yao51202502022-12-12 06:11:46 +0000865 return OK;
866}
867
868int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000869 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800870 int32_t mixerBurstCount = 0;
871 if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
872 return mixerBurstCount;
873 }
874 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000875}
876
877int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000878 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800879 int32_t hardwareBurstMinUsec = 0;
880 if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
881 return hardwareBurstMinUsec;
882 }
883 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000884}
885
886error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000887 TIME_CHECK();
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700888 if (!mModule) return NO_INIT;
889 int32_t aidlHwAvSync;
890 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
891 return VALUE_OR_RETURN_STATUS(
892 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +0000893}
894
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000895status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
896 TIME_CHECK();
897 if (!mModule) return NO_INIT;
898 return mModule->dump(fd, Args(args).args(), args.size());
David Li9cf5e622023-03-21 00:51:10 +0800899}
Shunkai Yao51202502022-12-12 06:11:46 +0000900
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700901int32_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000902 TIME_CHECK();
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700903 if (!mModule) return NO_INIT;
904 if (supports == nullptr) {
905 return BAD_VALUE;
906 }
907 return statusTFromBinderStatus(mModule->supportsVariableLatency(supports));
Shunkai Yao51202502022-12-12 06:11:46 +0000908}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000909
Mikhail Naganove93a0862023-03-15 17:06:59 -0700910status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
911 TIME_CHECK();
912 if (!mModule) return NO_INIT;
913 if (port == nullptr) {
914 return BAD_VALUE;
915 }
916 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
917 ::aidl::android::AudioPortDirection::INPUT;
918 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
919 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
920 if (aidlPort.ext.getTag() != AudioPortExt::device) {
921 ALOGE("%s: provided port is not a device port (module %s): %s",
922 __func__, mInstance.c_str(), aidlPort.toString().c_str());
923 return BAD_VALUE;
924 }
925 if (connected) {
926 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
927 // Reset the device address to find the "template" port.
928 matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
929 auto portsIt = findPort(matchDevice);
930 if (portsIt == mPorts.end()) {
931 ALOGW("%s: device port for device %s is not found in the module %s",
932 __func__, matchDevice.toString().c_str(), mInstance.c_str());
933 return BAD_VALUE;
934 }
935 // Use the ID of the "template" port, use all the information from the provided port.
936 aidlPort.id = portsIt->first;
937 AudioPort connectedPort;
938 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
939 aidlPort, &connectedPort)));
940 const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
941 LOG_ALWAYS_FATAL_IF(!inserted,
942 "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
943 __func__, mInstance.c_str(), connectedPort.toString().c_str(),
944 it->second.toString().c_str());
945 } else { // !connected
946 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
947 auto portsIt = findPort(matchDevice);
948 if (portsIt == mPorts.end()) {
949 ALOGW("%s: device port for device %s is not found in the module %s",
950 __func__, matchDevice.toString().c_str(), mInstance.c_str());
951 return BAD_VALUE;
952 }
953 // Any streams opened on the external device must be closed by this time,
954 // thus we can clean up patches and port configs that were created for them.
955 resetUnusedPatchesAndPortConfigs();
956 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
957 portsIt->second.id)));
958 mPorts.erase(portsIt);
959 }
Mikhail Naganov289468a2023-03-29 10:06:15 -0700960 return updateRoutes();
Mikhail Naganove93a0862023-03-15 17:06:59 -0700961}
962
963status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
964 TIME_CHECK();
965 if (!mModule) return NO_INIT;
966 ModuleDebug debug{ .simulateDeviceConnections = enabled };
967 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
968 // This is important to log as it affects HAL behavior.
969 if (status == OK) {
970 ALOGI("%s: set enabled: %d", __func__, enabled);
971 } else {
972 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
973 }
974 return status;
975}
976
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800977bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
978 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
979 return p.ext.get<AudioPortExt::Tag::device>().device == device;
980}
981
982bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
983 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
984 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
985 return p.portId == mDefaultInputPortId;
986 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
987 return p.portId == mDefaultOutputPortId;
988 }
989 return p.ext.get<AudioPortExt::Tag::device>().device == device;
990}
991
David Lia8675d42023-03-30 21:08:06 +0800992status_t DeviceHalAidl::createOrUpdatePortConfig(
993 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool* created) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800994 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800995 AudioPortConfig appliedPortConfig;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800996 bool applied = false;
997 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800998 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800999 if (!applied) {
1000 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001001 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001002 if (!applied) {
1003 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001004 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001005 return NO_INIT;
1006 }
1007 }
David Lia8675d42023-03-30 21:08:06 +08001008
1009 int32_t id = appliedPortConfig.id;
1010 if (requestedPortConfig.id != 0 && requestedPortConfig.id != id) {
1011 LOG_ALWAYS_FATAL("%s: requested port config id %d changed to %d", __func__,
1012 requestedPortConfig.id, id);
1013 }
1014
1015 auto [it, inserted] = mPortConfigs.insert_or_assign(std::move(id),
1016 std::move(appliedPortConfig));
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001017 *result = it;
David Lia8675d42023-03-30 21:08:06 +08001018 *created = inserted;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001019 return OK;
1020}
1021
1022status_t DeviceHalAidl::findOrCreatePatch(
1023 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
1024 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
1025 requestedPatch.sourcePortConfigIds.end());
1026 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
1027 requestedPatch.sinkPortConfigIds.end());
1028 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
1029}
1030
1031status_t DeviceHalAidl::findOrCreatePatch(
1032 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
1033 AudioPatch* patch, bool* created) {
1034 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
1035 if (patchIt == mPatches.end()) {
1036 TIME_CHECK();
1037 AudioPatch requestedPatch, appliedPatch;
1038 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
1039 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
1040 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
1041 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
1042 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
1043 requestedPatch, &appliedPatch)));
1044 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
1045 *created = true;
1046 } else {
1047 *created = false;
1048 }
1049 *patch = patchIt->second;
1050 return OK;
1051}
1052
jiabin9c07faf2023-04-26 22:00:44 +00001053status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device, const AudioConfig* config,
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001054 AudioPortConfig* portConfig, bool* created) {
1055 auto portConfigIt = findPortConfig(device);
1056 if (portConfigIt == mPortConfigs.end()) {
1057 auto portsIt = findPort(device);
1058 if (portsIt == mPorts.end()) {
1059 ALOGE("%s: device port for device %s is not found in the module %s",
1060 __func__, device.toString().c_str(), mInstance.c_str());
1061 return BAD_VALUE;
1062 }
1063 AudioPortConfig requestedPortConfig;
1064 requestedPortConfig.portId = portsIt->first;
jiabin9c07faf2023-04-26 22:00:44 +00001065 if (config != nullptr) {
1066 setPortConfigFromConfig(&requestedPortConfig, *config);
1067 }
David Lia8675d42023-03-30 21:08:06 +08001068 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1069 created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001070 } else {
1071 *created = false;
1072 }
1073 *portConfig = portConfigIt->second;
1074 return OK;
1075}
1076
1077status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001078 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001079 AudioSource source, const std::set<int32_t>& destinationPortIds,
1080 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001081 // These flags get removed one by one in this order when retrying port finding.
1082 static const std::vector<AudioInputFlags> kOptionalInputFlags{
1083 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001084 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001085 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001086 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
1087 AudioIoFlags matchFlags = flags.value();
Mikhail Naganov289468a2023-03-29 10:06:15 -07001088 auto portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001089 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
1090 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
1091 if (!isBitPositionFlagSet(
1092 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
1093 ++optionalInputFlagsIt;
1094 continue;
1095 }
1096 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
1097 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
Mikhail Naganov289468a2023-03-29 10:06:15 -07001098 portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001099 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
1100 "retried with flags %s", __func__, config.toString().c_str(),
1101 flags.value().toString().c_str(), mInstance.c_str(),
1102 matchFlags.toString().c_str());
1103 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001104 if (portsIt == mPorts.end()) {
1105 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001106 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001107 mInstance.c_str());
1108 return BAD_VALUE;
1109 }
1110 AudioPortConfig requestedPortConfig;
1111 requestedPortConfig.portId = portsIt->first;
1112 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001113 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001114 if (matchFlags.getTag() == AudioIoFlags::Tag::input
1115 && source != AudioSource::SYS_RESERVED_INVALID) {
1116 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
1117 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
1118 }
David Lia8675d42023-03-30 21:08:06 +08001119 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1120 created));
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001121 } else if (!flags.has_value()) {
1122 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
1123 "and was not created as flags are not specified",
1124 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
1125 return BAD_VALUE;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001126 } else {
David Lia8675d42023-03-30 21:08:06 +08001127 AudioPortConfig requestedPortConfig = portConfigIt->second;
1128 if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
1129 AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
1130 if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
1131 source != AudioSource::SYS_RESERVED_INVALID) {
1132 mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
1133 }
1134 }
1135
1136 if (requestedPortConfig != portConfigIt->second) {
1137 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1138 created));
1139 } else {
1140 *created = false;
1141 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001142 }
1143 *portConfig = portConfigIt->second;
1144 return OK;
1145}
1146
1147status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001148 const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
1149 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001150 using Tag = AudioPortExt::Tag;
1151 if (requestedPortConfig.ext.getTag() == Tag::mix) {
1152 if (const auto& p = requestedPortConfig;
1153 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001154 !p.format.has_value()) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001155 ALOGW("%s: provided mix port config is not fully specified: %s",
1156 __func__, p.toString().c_str());
1157 return BAD_VALUE;
1158 }
1159 AudioConfig config;
1160 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001161 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
1162 AudioPortMixExtUseCase::Tag::source ?
1163 requestedPortConfig.ext.get<Tag::mix>().usecase.
1164 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001165 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001166 requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
1167 portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001168 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
1169 return findOrCreatePortConfig(
jiabin9c07faf2023-04-26 22:00:44 +00001170 requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
1171 portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001172 }
1173 ALOGW("%s: unsupported audio port config: %s",
1174 __func__, requestedPortConfig.toString().c_str());
1175 return BAD_VALUE;
1176}
1177
1178DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
1179 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
1180 return std::find_if(mPatches.begin(), mPatches.end(),
1181 [&](const auto& pair) {
1182 const auto& p = pair.second;
1183 std::set<int32_t> patchSrcs(
1184 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
1185 std::set<int32_t> patchSinks(
1186 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
1187 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
1188}
1189
1190DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001191 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1192 return mPorts.find(mDefaultInputPortId);
1193 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1194 return mPorts.find(mDefaultOutputPortId);
1195 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001196 return std::find_if(mPorts.begin(), mPorts.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001197 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001198}
1199
1200DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001201 const AudioConfig& config, const AudioIoFlags& flags,
1202 const std::set<int32_t>& destinationPortIds) {
Mikhail Naganove93a0862023-03-15 17:06:59 -07001203 auto belongsToProfile = [&config](const AudioProfile& prof) {
1204 return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
1205 (config.base.channelMask.getTag() == AudioChannelLayout::none ||
1206 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
1207 config.base.channelMask) != prof.channelMasks.end()) &&
1208 (config.base.sampleRate == 0 ||
1209 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
1210 config.base.sampleRate) != prof.sampleRates.end());
1211 };
jiabin9c07faf2023-04-26 22:00:44 +00001212 static const std::vector<AudioOutputFlags> kOptionalOutputFlags{AudioOutputFlags::BIT_PERFECT};
1213 int optionalFlags = 0;
1214 auto flagMatches = [&flags, &optionalFlags](const AudioIoFlags& portFlags) {
1215 // Ports should be able to match if the optional flags are not requested.
1216 return portFlags == flags ||
1217 (portFlags.getTag() == AudioIoFlags::Tag::output &&
1218 AudioIoFlags::make<AudioIoFlags::Tag::output>(
1219 portFlags.get<AudioIoFlags::Tag::output>() &
1220 ~optionalFlags) == flags);
1221 };
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001222 auto matcher = [&](const auto& pair) {
1223 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001224 return p.ext.getTag() == AudioPortExt::Tag::mix &&
jiabin9c07faf2023-04-26 22:00:44 +00001225 flagMatches(p.flags) &&
Mikhail Naganov289468a2023-03-29 10:06:15 -07001226 (destinationPortIds.empty() ||
1227 std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
1228 [&](const int32_t destId) { return mRoutingMatrix.count(
1229 std::make_pair(p.id, destId)) != 0; })) &&
Mikhail Naganove93a0862023-03-15 17:06:59 -07001230 (p.profiles.empty() ||
1231 std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
1232 p.profiles.end()); };
jiabin9c07faf2023-04-26 22:00:44 +00001233 auto result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1234 if (result == mPorts.end() && flags.getTag() == AudioIoFlags::Tag::output) {
1235 auto optionalOutputFlagsIt = kOptionalOutputFlags.begin();
1236 while (result == mPorts.end() && optionalOutputFlagsIt != kOptionalOutputFlags.end()) {
1237 if (isBitPositionFlagSet(
1238 flags.get<AudioIoFlags::Tag::output>(), *optionalOutputFlagsIt)) {
1239 // If the flag is set by the request, it must be matched.
1240 ++optionalOutputFlagsIt;
1241 continue;
1242 }
1243 optionalFlags |= makeBitPositionFlagMask(*optionalOutputFlagsIt++);
1244 result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1245 ALOGI("%s: port for config %s, flags %s was not found in the module %s, "
1246 "retried with excluding optional flags %#x", __func__, config.toString().c_str(),
1247 flags.toString().c_str(), mInstance.c_str(), optionalFlags);
1248 }
1249 }
1250 return result;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001251}
1252
1253DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001254 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001255 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001256}
1257
1258DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001259 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001260 using Tag = AudioPortExt::Tag;
1261 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
1262 [&](const auto& pair) {
1263 const auto& p = pair.second;
1264 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
1265 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
1266 !p.format.has_value() || !p.flags.has_value(),
1267 "%s: stored mix port config is not fully specified: %s",
1268 __func__, p.toString().c_str());
1269 return p.ext.getTag() == Tag::mix &&
1270 isConfigEqualToPortConfig(config, p) &&
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001271 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001272 p.ext.template get<Tag::mix>().handle == ioHandle; });
1273}
Mikhail Naganove93a0862023-03-15 17:06:59 -07001274
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001275void DeviceHalAidl::resetPatch(int32_t patchId) {
1276 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1277 mPatches.erase(it);
1278 TIME_CHECK();
1279 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1280 ALOGE("%s: error while resetting patch %d: %s",
1281 __func__, patchId, status.getDescription().c_str());
1282 }
1283 return;
1284 }
1285 ALOGE("%s: patch id %d not found", __func__, patchId);
1286}
1287
1288void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1289 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1290 mPortConfigs.erase(it);
1291 TIME_CHECK();
1292 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1293 !status.isOk()) {
1294 ALOGE("%s: error while resetting port config %d: %s",
1295 __func__, portConfigId, status.getDescription().c_str());
1296 }
1297 return;
1298 }
1299 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1300}
1301
Mikhail Naganove93a0862023-03-15 17:06:59 -07001302void DeviceHalAidl::resetUnusedPatches() {
1303 // Since patches can be created independently of streams via 'createAudioPatch',
1304 // here we only clean up patches for released streams.
1305 for (auto it = mStreams.begin(); it != mStreams.end(); ) {
1306 if (auto streamSp = it->first.promote(); streamSp) {
1307 ++it;
1308 } else {
1309 resetPatch(it->second);
1310 it = mStreams.erase(it);
1311 }
1312 }
1313}
1314
1315void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
1316 resetUnusedPatches();
1317 resetUnusedPortConfigs();
1318}
1319
1320void DeviceHalAidl::resetUnusedPortConfigs() {
1321 // The assumption is that port configs are used to create patches
1322 // (or to open streams, but that involves creation of patches, too). Thus,
1323 // orphaned port configs can and should be reset.
1324 std::set<int32_t> portConfigIds;
1325 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
1326 std::inserter(portConfigIds, portConfigIds.end()),
1327 [](const auto& pcPair) { return pcPair.first; });
1328 for (const auto& p : mPatches) {
1329 for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
1330 for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
1331 }
jiabin9c07faf2023-04-26 22:00:44 +00001332 for (int32_t id : mInitialPortConfigIds) {
1333 portConfigIds.erase(id);
1334 }
Mikhail Naganove93a0862023-03-15 17:06:59 -07001335 for (int32_t id : portConfigIds) resetPortConfig(id);
1336}
1337
Mikhail Naganov289468a2023-03-29 10:06:15 -07001338status_t DeviceHalAidl::updateRoutes() {
1339 TIME_CHECK();
Mikhail Naganov289468a2023-03-29 10:06:15 -07001340 RETURN_STATUS_IF_ERROR(
Mikhail Naganovf83b9742023-04-24 13:06:04 -07001341 statusTFromBinderStatus(mModule->getAudioRoutes(&mRoutes)));
1342 ALOGW_IF(mRoutes.empty(), "%s: module %s returned an empty list of audio routes",
Mikhail Naganov289468a2023-03-29 10:06:15 -07001343 __func__, mInstance.c_str());
1344 mRoutingMatrix.clear();
Mikhail Naganovf83b9742023-04-24 13:06:04 -07001345 for (const auto& r : mRoutes) {
Mikhail Naganov289468a2023-03-29 10:06:15 -07001346 for (auto portId : r.sourcePortIds) {
1347 mRoutingMatrix.emplace(r.sinkPortId, portId);
1348 mRoutingMatrix.emplace(portId, r.sinkPortId);
1349 }
1350 }
1351 return OK;
1352}
1353
Mikhail Naganovdfd594e2023-02-08 16:59:41 -08001354void DeviceHalAidl::clearCallbacks(void* cookie) {
1355 std::lock_guard l(mLock);
1356 mCallbacks.erase(cookie);
1357}
1358
1359sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1360 return getCallbackImpl(cookie, &Callbacks::out);
1361}
1362
1363void DeviceHalAidl::setStreamOutCallback(
1364 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1365 setCallbackImpl(cookie, &Callbacks::out, cb);
1366}
1367
1368sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1369 void* cookie) {
1370 return getCallbackImpl(cookie, &Callbacks::event);
1371}
1372
1373void DeviceHalAidl::setStreamOutEventCallback(
1374 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1375 setCallbackImpl(cookie, &Callbacks::event, cb);
1376}
1377
1378sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1379 void* cookie) {
1380 return getCallbackImpl(cookie, &Callbacks::latency);
1381}
1382
1383void DeviceHalAidl::setStreamOutLatencyModeCallback(
1384 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1385 setCallbackImpl(cookie, &Callbacks::latency, cb);
1386}
1387
1388template<class C>
1389sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1390 std::lock_guard l(mLock);
1391 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1392 return ((it->second).*field).promote();
1393 }
1394 return nullptr;
1395}
1396template<class C>
1397void DeviceHalAidl::setCallbackImpl(
1398 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1399 std::lock_guard l(mLock);
1400 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1401 (it->second).*field = cb;
1402 }
1403}
1404
Mikhail Naganov31d46652023-01-10 18:29:25 +00001405} // namespace android