blob: 865d1d679b541bf79c27c7e0b6271b055534b564 [file] [log] [blame]
Shunkai Yao51202502022-12-12 06:11:46 +00001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "DeviceHalAidl"
Vlad Popa03bd5bc2023-01-17 16:16:51 +010018// #define LOG_NDEBUG 0
Shunkai Yao51202502022-12-12 06:11:46 +000019
Mikhail Naganovf56ce782023-01-25 11:29:11 -080020#include <algorithm>
21#include <forward_list>
22
Mikhail Naganovb0c55252023-02-08 16:59:41 -080023#include <aidl/android/hardware/audio/core/BnStreamCallback.h>
24#include <aidl/android/hardware/audio/core/BnStreamOutEventCallback.h>
Mikhail Naganovfab697c2023-01-11 19:33:13 +000025#include <aidl/android/hardware/audio/core/StreamDescriptor.h>
26#include <error/expected_utils.h>
27#include <media/AidlConversionCppNdk.h>
Mikhail Naganovbfbb75b2023-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 Naganov8bd806e2023-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 Naganovb1ddbb02023-03-15 17:06:59 -070038using aidl::android::media::audio::common::AudioChannelLayout;
Mikhail Naganovf56ce782023-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 Naganov8bd806e2023-01-30 12:33:18 -080042using aidl::android::media::audio::common::AudioDeviceType;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -070043using aidl::android::media::audio::common::AudioFormatType;
Mikhail Naganov8bd806e2023-01-30 12:33:18 -080044using aidl::android::media::audio::common::AudioInputFlags;
Mikhail Naganovf56ce782023-01-25 11:29:11 -080045using aidl::android::media::audio::common::AudioIoFlags;
Mikhail Naganovb0c55252023-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 Naganovf56ce782023-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 Naganov8bd806e2023-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 Naganovb1ddbb02023-03-15 17:06:59 -070058using aidl::android::media::audio::common::AudioProfile;
Mikhail Naganovf56ce782023-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 Naganovb1ddbb02023-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 Naganovf56ce782023-01-25 11:29:11 -080068using aidl::android::hardware::audio::common::RecordTrackMetadata;
69using aidl::android::hardware::audio::core::AudioPatch;
Mikhail Naganovecfafb72023-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 Naganovb1ddbb02023-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 Naganovf56ce782023-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 Naganov2d814892023-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;
107 return cpp;
108}
109
Mikhail Naganovffd97712023-05-03 17:45:36 -0700110template<typename T>
111std::shared_ptr<T> retrieveSubInterface(const std::shared_ptr<IModule>& module,
112 ::ndk::ScopedAStatus (IModule::*getT)(std::shared_ptr<T>*)) {
113 if (module != nullptr) {
114 std::shared_ptr<T> instance;
115 if (auto status = (module.get()->*getT)(&instance); status.isOk()) {
116 return instance;
117 }
118 }
119 return nullptr;
120}
121
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800122} // namespace
123
Mikhail Naganovffd97712023-05-03 17:45:36 -0700124DeviceHalAidl::DeviceHalAidl(const std::string& instance, const std::shared_ptr<IModule>& module)
125 : ConversionHelperAidl("DeviceHalAidl"),
126 mInstance(instance), mModule(module),
127 mTelephony(retrieveSubInterface<ITelephony>(module, &IModule::getTelephony)) {
128}
129
Mikhail Naganov2d814892023-04-24 13:06:04 -0700130status_t DeviceHalAidl::getAudioPorts(std::vector<media::audio::common::AudioPort> *ports) {
131 auto convertAudioPortFromMap = [](const Ports::value_type& pair) {
132 return ndk2cpp_AudioPort(pair.second);
133 };
134 return ::aidl::android::convertRange(mPorts.begin(), mPorts.end(), ports->begin(),
135 convertAudioPortFromMap);
136}
137
138status_t DeviceHalAidl::getAudioRoutes(std::vector<media::AudioRoute> *routes) {
139 *routes = VALUE_OR_RETURN_STATUS(
140 ::aidl::android::convertContainer<std::vector<media::AudioRoute>>(
141 mRoutes, ndk2cpp_AudioRoute));
142 return OK;
143}
144
Mikhail Naganovffd97712023-05-03 17:45:36 -0700145status_t DeviceHalAidl::getSupportedModes(std::vector<media::audio::common::AudioMode> *modes) {
146 TIME_CHECK();
147 if (modes == nullptr) {
148 return BAD_VALUE;
149 }
150 if (mModule == nullptr) return NO_INIT;
151 if (mTelephony == nullptr) return INVALID_OPERATION;
152 std::vector<AudioMode> aidlModes;
153 RETURN_STATUS_IF_ERROR(
154 statusTFromBinderStatus(mTelephony->getSupportedAudioModes(&aidlModes)));
155 *modes = VALUE_OR_RETURN_STATUS(
156 ::aidl::android::convertContainer<std::vector<media::audio::common::AudioMode>>(
157 aidlModes, ndk2cpp_AudioMode));
158 return OK;
159}
160
Mikhail Naganov31d46652023-01-10 18:29:25 +0000161status_t DeviceHalAidl::getSupportedDevices(uint32_t*) {
162 // Obsolete.
163 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +0000164}
165
166status_t DeviceHalAidl::initCheck() {
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800167 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000168 if (mModule == nullptr) return NO_INIT;
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800169 std::vector<AudioPort> ports;
Mikhail Naganov2d814892023-04-24 13:06:04 -0700170 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800171 ALOGW_IF(ports.empty(), "%s: module %s returned an empty list of audio ports",
172 __func__, mInstance.c_str());
173 std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()),
174 [](const auto& p) { return std::make_pair(p.id, p); });
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800175 mDefaultInputPortId = mDefaultOutputPortId = -1;
176 const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
177 for (const auto& pair : mPorts) {
178 const auto& p = pair.second;
179 if (p.ext.getTag() == AudioPortExt::Tag::device &&
180 (p.ext.get<AudioPortExt::Tag::device>().flags & defaultDeviceFlag) != 0) {
181 if (p.flags.getTag() == AudioIoFlags::Tag::input) {
182 mDefaultInputPortId = p.id;
183 } else if (p.flags.getTag() == AudioIoFlags::Tag::output) {
184 mDefaultOutputPortId = p.id;
185 }
186 }
187 }
188 ALOGI("%s: module %s default port ids: input %d, output %d",
189 __func__, mInstance.c_str(), mDefaultInputPortId, mDefaultOutputPortId);
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700190 RETURN_STATUS_IF_ERROR(updateRoutes());
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800191 std::vector<AudioPortConfig> portConfigs;
192 RETURN_STATUS_IF_ERROR(
193 statusTFromBinderStatus(mModule->getAudioPortConfigs(&portConfigs))); // OK if empty
194 std::transform(portConfigs.begin(), portConfigs.end(),
195 std::inserter(mPortConfigs, mPortConfigs.end()),
196 [](const auto& p) { return std::make_pair(p.id, p); });
jiabin2248fa12023-04-27 22:04:16 +0000197 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
198 std::inserter(mInitialPortConfigIds, mInitialPortConfigIds.end()),
199 [](const auto& pcPair) { return pcPair.first; });
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800200 std::vector<AudioPatch> patches;
201 RETURN_STATUS_IF_ERROR(
202 statusTFromBinderStatus(mModule->getAudioPatches(&patches))); // OK if empty
203 std::transform(patches.begin(), patches.end(),
204 std::inserter(mPatches, mPatches.end()),
205 [](const auto& p) { return std::make_pair(p.id, p); });
Shunkai Yao51202502022-12-12 06:11:46 +0000206 return OK;
207}
208
209status_t DeviceHalAidl::setVoiceVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000210 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000211 if (!mModule) return NO_INIT;
Mikhail Naganovffd97712023-05-03 17:45:36 -0700212 if (mTelephony == nullptr) return INVALID_OPERATION;
213 ITelephony::TelecomConfig inConfig{ .voiceVolume = Float{volume} }, outConfig;
214 RETURN_STATUS_IF_ERROR(
215 statusTFromBinderStatus(mTelephony->setTelecomConfig(inConfig, &outConfig)));
216 ALOGW_IF(outConfig.voiceVolume.has_value() && volume != outConfig.voiceVolume.value().value,
217 "%s: the resulting voice volume %f is not the same as requested %f",
218 __func__, outConfig.voiceVolume.value().value, volume);
219 return OK;
Shunkai Yao51202502022-12-12 06:11:46 +0000220}
221
222status_t DeviceHalAidl::setMasterVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000223 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000224 if (!mModule) return NO_INIT;
225 return statusTFromBinderStatus(mModule->setMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000226}
227
228status_t DeviceHalAidl::getMasterVolume(float *volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000229 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000230 if (!mModule) return NO_INIT;
231 return statusTFromBinderStatus(mModule->getMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000232}
233
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000234status_t DeviceHalAidl::setMode(audio_mode_t mode) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000235 TIME_CHECK();
236 if (!mModule) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000237 AudioMode audioMode = VALUE_OR_FATAL(::aidl::android::legacy2aidl_audio_mode_t_AudioMode(mode));
Mikhail Naganovffd97712023-05-03 17:45:36 -0700238 if (mTelephony != nullptr) {
239 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mTelephony->switchAudioMode(audioMode)));
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000240 }
241 return statusTFromBinderStatus(mModule->updateAudioMode(audioMode));
Shunkai Yao51202502022-12-12 06:11:46 +0000242}
243
244status_t DeviceHalAidl::setMicMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000245 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000246 if (!mModule) return NO_INIT;
247 return statusTFromBinderStatus(mModule->setMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000248}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000249
Shunkai Yao51202502022-12-12 06:11:46 +0000250status_t DeviceHalAidl::getMicMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000251 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000252 if (!mModule) return NO_INIT;
253 return statusTFromBinderStatus(mModule->getMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000254}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000255
Shunkai Yao51202502022-12-12 06:11:46 +0000256status_t DeviceHalAidl::setMasterMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000257 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000258 if (!mModule) return NO_INIT;
259 return statusTFromBinderStatus(mModule->setMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000260}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000261
Shunkai Yao51202502022-12-12 06:11:46 +0000262status_t DeviceHalAidl::getMasterMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000263 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000264 if (!mModule) return NO_INIT;
265 return statusTFromBinderStatus(mModule->getMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000266}
267
Mikhail Naganov31d46652023-01-10 18:29:25 +0000268status_t DeviceHalAidl::setParameters(const String8& kvPairs __unused) {
269 TIME_CHECK();
270 if (!mModule) return NO_INIT;
271 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000272 return OK;
273}
274
Mikhail Naganov31d46652023-01-10 18:29:25 +0000275status_t DeviceHalAidl::getParameters(const String8& keys __unused, String8 *values) {
276 TIME_CHECK();
277 values->clear();
278 if (!mModule) return NO_INIT;
279 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000280 return OK;
281}
282
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800283namespace {
284
285class Cleanup {
286 public:
287 typedef void (DeviceHalAidl::*Cleaner)(int32_t);
288
289 Cleanup(DeviceHalAidl* device, Cleaner cleaner, int32_t id) :
290 mDevice(device), mCleaner(cleaner), mId(id) {}
291 ~Cleanup() { clean(); }
292 void clean() {
293 if (mDevice != nullptr) (mDevice->*mCleaner)(mId);
294 disarm();
295 }
296 void disarm() { mDevice = nullptr; }
297
298 private:
299 DeviceHalAidl* mDevice;
300 const Cleaner mCleaner;
301 const int32_t mId;
302};
303
304} // namespace
305
306// Since the order of container elements destruction is unspecified,
307// ensure that cleanups are performed from the most recent one and upwards.
308// This is the same as if there were individual Cleanup instances on the stack,
309// however the bonus is that we can disarm all of them with just one statement.
310class DeviceHalAidl::Cleanups : public std::forward_list<Cleanup> {
311 public:
312 ~Cleanups() { for (auto& c : *this) c.clean(); }
313 void disarmAll() { for (auto& c : *this) c.disarm(); }
314};
315
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800316status_t DeviceHalAidl::getInputBufferSize(const struct audio_config* config, size_t* size) {
317 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
318 if (size == nullptr) return BAD_VALUE;
319 TIME_CHECK();
320 if (!mModule) return NO_INIT;
321 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
322 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
323 AudioDevice aidlDevice;
324 aidlDevice.type.type = AudioDeviceType::IN_DEFAULT;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800325 AudioSource aidlSource = AudioSource::DEFAULT;
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800326 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
327 AudioPortConfig mixPortConfig;
328 Cleanups cleanups;
329 audio_config writableConfig = *config;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700330 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800331 RETURN_STATUS_IF_ERROR(prepareToOpenStream(0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700332 &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800333 *size = aidlConfig.frameCount *
334 getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
335 // Do not disarm cleanups to release temporary port configs.
336 return OK;
337}
338
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800339status_t DeviceHalAidl::prepareToOpenStream(
340 int32_t aidlHandle, const AudioDevice& aidlDevice, const AudioIoFlags& aidlFlags,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800341 AudioSource aidlSource, struct audio_config* config,
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800342 Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700343 AudioPatch* aidlPatch) {
344 ALOGD("%p %s::%s: handle %d, device %s, flags %s, source %s, config %s, mix port config %s",
345 this, getClassName().c_str(), __func__, aidlHandle, aidlDevice.toString().c_str(),
346 aidlFlags.toString().c_str(), toString(aidlSource).c_str(),
347 aidlConfig->toString().c_str(), mixPortConfig->toString().c_str());
jiabin2248fa12023-04-27 22:04:16 +0000348 resetUnusedPatchesAndPortConfigs();
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800349 const bool isInput = aidlFlags.getTag() == AudioIoFlags::Tag::input;
350 // Find / create AudioPortConfigs for the device port and the mix port,
351 // then find / create a patch between them, and open a stream on the mix port.
352 AudioPortConfig devicePortConfig;
353 bool created = false;
jiabin2248fa12023-04-27 22:04:16 +0000354 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, aidlConfig,
355 &devicePortConfig, &created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800356 if (created) {
357 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
358 }
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800359 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*aidlConfig, aidlFlags, aidlHandle, aidlSource,
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700360 std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800361 if (created) {
362 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
363 }
364 setConfigFromPortConfig(aidlConfig, *mixPortConfig);
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800365 if (isInput) {
366 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700367 {devicePortConfig.id}, {mixPortConfig->id}, aidlPatch, &created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800368 } else {
369 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700370 {mixPortConfig->id}, {devicePortConfig.id}, aidlPatch, &created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800371 }
372 if (created) {
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700373 cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, aidlPatch->id);
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800374 }
375 if (aidlConfig->frameCount <= 0) {
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700376 aidlConfig->frameCount = aidlPatch->minimumStreamBufferSizeFrames;
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800377 }
378 *config = VALUE_OR_RETURN_STATUS(
379 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(*aidlConfig, isInput));
380 return OK;
381}
382
Mikhail Naganovb0c55252023-02-08 16:59:41 -0800383namespace {
384
385class StreamCallbackBase {
386 protected:
387 explicit StreamCallbackBase(const sp<CallbackBroker>& broker) : mBroker(broker) {}
388 public:
389 void* getCookie() const { return mCookie; }
390 void setCookie(void* cookie) { mCookie = cookie; }
391 sp<CallbackBroker> getBroker() const {
392 if (void* cookie = mCookie; cookie != nullptr) return mBroker.promote();
393 return nullptr;
394 }
395 private:
396 const wp<CallbackBroker> mBroker;
397 std::atomic<void*> mCookie;
398};
399
400template<class C>
401class StreamCallbackBaseHelper {
402 protected:
403 explicit StreamCallbackBaseHelper(const StreamCallbackBase& base) : mBase(base) {}
404 sp<C> getCb(const sp<CallbackBroker>& broker, void* cookie);
405 using CbRef = const sp<C>&;
406 ndk::ScopedAStatus runCb(const std::function<void(CbRef cb)>& f) {
407 if (auto cb = getCb(mBase.getBroker(), mBase.getCookie()); cb != nullptr) f(cb);
408 return ndk::ScopedAStatus::ok();
409 }
410 private:
411 const StreamCallbackBase& mBase;
412};
413
414template<>
415sp<StreamOutHalInterfaceCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>::getCb(
416 const sp<CallbackBroker>& broker, void* cookie) {
417 if (broker != nullptr) return broker->getStreamOutCallback(cookie);
418 return nullptr;
419}
420
421template<>
422sp<StreamOutHalInterfaceEventCallback>
423StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::getCb(
424 const sp<CallbackBroker>& broker, void* cookie) {
425 if (broker != nullptr) return broker->getStreamOutEventCallback(cookie);
426 return nullptr;
427}
428
429template<>
430sp<StreamOutHalInterfaceLatencyModeCallback>
431StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::getCb(
432 const sp<CallbackBroker>& broker, void* cookie) {
433 if (broker != nullptr) return broker->getStreamOutLatencyModeCallback(cookie);
434 return nullptr;
435}
436
437/*
438Note on the callback ownership.
439
440In the Binder ownership model, the server implementation is kept alive
441as long as there is any client (proxy object) alive. This is done by
442incrementing the refcount of the server-side object by the Binder framework.
443When it detects that the last client is gone, it decrements the refcount back.
444
445Thus, it is not needed to keep any references to StreamCallback on our
446side (after we have sent an instance to the client), because we are
447the server-side. The callback object will be kept alive as long as the HAL server
448holds a strong ref to IStreamCallback proxy.
449*/
450
451class OutputStreamCallbackAidl : public StreamCallbackBase,
452 public StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>,
453 public ::aidl::android::hardware::audio::core::BnStreamCallback {
454 public:
455 explicit OutputStreamCallbackAidl(const sp<CallbackBroker>& broker)
456 : StreamCallbackBase(broker),
457 StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>(
458 *static_cast<StreamCallbackBase*>(this)) {}
459 ndk::ScopedAStatus onTransferReady() override {
460 return runCb([](CbRef cb) { cb->onWriteReady(); });
461 }
462 ndk::ScopedAStatus onError() override {
463 return runCb([](CbRef cb) { cb->onError(); });
464 }
465 ndk::ScopedAStatus onDrainReady() override {
466 return runCb([](CbRef cb) { cb->onDrainReady(); });
467 }
468};
469
470class OutputStreamEventCallbackAidl :
471 public StreamCallbackBase,
472 public StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>,
473 public StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>,
474 public ::aidl::android::hardware::audio::core::BnStreamOutEventCallback {
475 public:
476 explicit OutputStreamEventCallbackAidl(const sp<CallbackBroker>& broker)
477 : StreamCallbackBase(broker),
478 StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>(
479 *static_cast<StreamCallbackBase*>(this)),
480 StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>(
481 *static_cast<StreamCallbackBase*>(this)) {}
482 ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& in_audioMetadata) override {
483 std::basic_string<uint8_t> halMetadata(in_audioMetadata.begin(), in_audioMetadata.end());
484 return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb(
485 [&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); });
486 }
487 ndk::ScopedAStatus onRecommendedLatencyModeChanged(
488 const std::vector<AudioLatencyMode>& in_modes) override {
489 auto halModes = VALUE_OR_FATAL(
490 ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
491 in_modes,
492 ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
493 return StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::runCb(
494 [&halModes](auto cb) { cb->onRecommendedLatencyModeChanged(halModes); });
495 }
496};
497
498} // namespace
499
Mikhail Naganov31d46652023-01-10 18:29:25 +0000500status_t DeviceHalAidl::openOutputStream(
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800501 audio_io_handle_t handle, audio_devices_t devices,
502 audio_output_flags_t flags, struct audio_config* config,
503 const char* address,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000504 sp<StreamOutHalInterface>* outStream) {
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800505 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000506 if (!outStream || !config) {
507 return BAD_VALUE;
508 }
509 TIME_CHECK();
510 if (!mModule) return NO_INIT;
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800511 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
512 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
513 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
514 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, false /*isInput*/));
515 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
516 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
517 int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
518 ::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
519 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
520 AudioPortConfig mixPortConfig;
521 Cleanups cleanups;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700522 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800523 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
524 AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700525 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800526 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
527 args.portConfigId = mixPortConfig.id;
Mikhail Naganovb0c55252023-02-08 16:59:41 -0800528 const bool isOffload = isBitPositionFlagSet(
529 aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD);
530 std::shared_ptr<OutputStreamCallbackAidl> streamCb;
531 if (isOffload) {
532 streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
533 }
534 auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
535 if (isOffload) {
536 args.offloadInfo = aidlConfig.offloadInfo;
537 args.callback = streamCb;
538 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800539 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovb0c55252023-02-08 16:59:41 -0800540 args.eventCallback = eventCb;
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800541 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
542 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800543 StreamContextAidl context(ret.desc, isOffload);
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800544 if (!context.isValid()) {
545 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
546 __func__, ret.desc.toString().c_str());
547 return NO_INIT;
548 }
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700549 *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganovb0c55252023-02-08 16:59:41 -0800550 std::move(ret.stream), this /*callbackBroker*/);
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700551 mStreams.insert(std::pair(*outStream, aidlPatch.id));
Mikhail Naganovb0c55252023-02-08 16:59:41 -0800552 void* cbCookie = (*outStream).get();
553 {
554 std::lock_guard l(mLock);
555 mCallbacks.emplace(cbCookie, Callbacks{});
556 }
557 if (streamCb) streamCb->setCookie(cbCookie);
558 eventCb->setCookie(cbCookie);
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800559 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000560 return OK;
561}
562
Mikhail Naganov31d46652023-01-10 18:29:25 +0000563status_t DeviceHalAidl::openInputStream(
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800564 audio_io_handle_t handle, audio_devices_t devices,
565 struct audio_config* config, audio_input_flags_t flags,
566 const char* address, audio_source_t source,
567 audio_devices_t outputDevice, const char* outputDeviceAddress,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000568 sp<StreamInHalInterface>* inStream) {
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800569 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000570 if (!inStream || !config) {
571 return BAD_VALUE;
572 }
573 TIME_CHECK();
574 if (!mModule) return NO_INIT;
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800575 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
576 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
577 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
578 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
579 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
580 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
581 int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
582 ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
583 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
584 AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
585 ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
586 AudioPortConfig mixPortConfig;
587 Cleanups cleanups;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700588 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800589 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700590 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800591 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
592 args.portConfigId = mixPortConfig.id;
593 RecordTrackMetadata aidlTrackMetadata{
594 .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
595 if (outputDevice != AUDIO_DEVICE_NONE) {
596 aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
597 ::aidl::android::legacy2aidl_audio_device_AudioDevice(
598 outputDevice, outputDeviceAddress));
599 }
600 args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
601 args.bufferSizeFrames = aidlConfig.frameCount;
602 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
603 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800604 StreamContextAidl context(ret.desc, false /*isAsynchronous*/);
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800605 if (!context.isValid()) {
606 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
607 __func__, ret.desc.toString().c_str());
608 return NO_INIT;
609 }
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700610 *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800611 std::move(ret.stream), this /*micInfoProvider*/);
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700612 mStreams.insert(std::pair(*inStream, aidlPatch.id));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800613 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000614 return OK;
615}
616
617status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
618 *supportsPatches = true;
619 return OK;
620}
621
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800622status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
623 const struct audio_port_config* sources,
624 unsigned int num_sinks,
625 const struct audio_port_config* sinks,
626 audio_patch_handle_t* patch) {
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800627 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000628 TIME_CHECK();
629 if (!mModule) return NO_INIT;
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800630 if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
631 sources == nullptr || sinks == nullptr || patch == nullptr) {
632 return BAD_VALUE;
633 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800634 // When the patch handle (*patch) is AUDIO_PATCH_HANDLE_NONE, it means
635 // the framework wants to create a new patch. The handle has to be generated
636 // by the HAL. Since handles generated this way can only be unique within
637 // a HAL module, the framework generates a globally unique handle, and maps
638 // it on the <HAL module, patch handle> pair.
639 // When the patch handle is set, it meant the framework intends to update
640 // an existing patch.
641 //
642 // This behavior corresponds to HAL module behavior, with the only difference
643 // that the HAL module uses `int32_t` for patch IDs. The following assert ensures
644 // that both the framework and the HAL use the same value for "no ID":
645 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
646 int32_t halPatchId = static_cast<int32_t>(*patch);
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800647
648 // Upon conversion, mix port configs contain audio configuration, while
649 // device port configs contain device address. This data is used to find
650 // or create HAL configs.
651 std::vector<AudioPortConfig> aidlSources, aidlSinks;
652 for (unsigned int i = 0; i < num_sources; ++i) {
653 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
654 sources[i].role, sources[i].type)) ==
655 ::aidl::android::AudioPortDirection::INPUT;
656 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
657 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
658 sources[i], isInput, 0)));
659 }
660 for (unsigned int i = 0; i < num_sinks; ++i) {
661 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
662 sinks[i].role, sinks[i].type)) ==
663 ::aidl::android::AudioPortDirection::INPUT;
664 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
665 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
666 sinks[i], isInput, 0)));
667 }
668 Cleanups cleanups;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800669 auto existingPatchIt = halPatchId != 0 ? mPatches.find(halPatchId): mPatches.end();
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800670 AudioPatch aidlPatch;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800671 if (existingPatchIt != mPatches.end()) {
672 aidlPatch = existingPatchIt->second;
673 aidlPatch.sourcePortConfigIds.clear();
674 aidlPatch.sinkPortConfigIds.clear();
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800675 }
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800676 ALOGD("%s: sources: %s, sinks: %s",
677 __func__, ::android::internal::ToString(aidlSources).c_str(),
678 ::android::internal::ToString(aidlSinks).c_str());
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800679 auto fillPortConfigs = [&](
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700680 const std::vector<AudioPortConfig>& configs,
681 const std::set<int32_t>& destinationPortIds,
682 std::vector<int32_t>* ids, std::set<int32_t>* portIds) -> status_t {
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800683 for (const auto& s : configs) {
684 AudioPortConfig portConfig;
685 bool created = false;
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700686 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
687 s, destinationPortIds, &portConfig, &created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800688 if (created) {
689 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, portConfig.id);
690 }
691 ids->push_back(portConfig.id);
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700692 if (portIds != nullptr) {
693 portIds->insert(portConfig.portId);
694 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800695 }
696 return OK;
697 };
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700698 // When looking up port configs, the destinationPortId is only used for mix ports.
699 // Thus, we process device port configs first, and look up the destination port ID from them.
700 bool sourceIsDevice = std::any_of(aidlSources.begin(), aidlSources.end(),
701 [](const auto& config) { return config.ext.getTag() == AudioPortExt::device; });
702 const std::vector<AudioPortConfig>& devicePortConfigs =
703 sourceIsDevice ? aidlSources : aidlSinks;
704 std::vector<int32_t>* devicePortConfigIds =
705 sourceIsDevice ? &aidlPatch.sourcePortConfigIds : &aidlPatch.sinkPortConfigIds;
706 const std::vector<AudioPortConfig>& mixPortConfigs =
707 sourceIsDevice ? aidlSinks : aidlSources;
708 std::vector<int32_t>* mixPortConfigIds =
709 sourceIsDevice ? &aidlPatch.sinkPortConfigIds : &aidlPatch.sourcePortConfigIds;
710 std::set<int32_t> devicePortIds;
711 RETURN_STATUS_IF_ERROR(fillPortConfigs(
712 devicePortConfigs, std::set<int32_t>(), devicePortConfigIds, &devicePortIds));
713 RETURN_STATUS_IF_ERROR(fillPortConfigs(
714 mixPortConfigs, devicePortIds, mixPortConfigIds, nullptr));
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800715 if (existingPatchIt != mPatches.end()) {
716 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
717 mModule->setAudioPatch(aidlPatch, &aidlPatch)));
718 existingPatchIt->second = aidlPatch;
719 } else {
720 bool created = false;
721 RETURN_STATUS_IF_ERROR(findOrCreatePatch(aidlPatch, &aidlPatch, &created));
722 // Since no cleanup of the patch is needed, 'created' is ignored.
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800723 halPatchId = aidlPatch.id;
724 *patch = static_cast<audio_patch_handle_t>(halPatchId);
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800725 }
726 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000727 return OK;
728}
729
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800730status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov8bd806e2023-01-30 12:33:18 -0800731 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000732 TIME_CHECK();
733 if (!mModule) return NO_INIT;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800734 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
735 if (patch == AUDIO_PATCH_HANDLE_NONE) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -0800736 return BAD_VALUE;
737 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800738 int32_t halPatchId = static_cast<int32_t>(patch);
739 auto patchIt = mPatches.find(halPatchId);
740 if (patchIt == mPatches.end()) {
741 ALOGE("%s: patch with id %d not found", __func__, halPatchId);
742 return BAD_VALUE;
743 }
744 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->resetAudioPatch(halPatchId)));
745 mPatches.erase(patchIt);
Shunkai Yao51202502022-12-12 06:11:46 +0000746 return OK;
747}
748
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700749status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
750 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000751 TIME_CHECK();
752 if (!mModule) return NO_INIT;
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700753 if (port == nullptr) {
754 return BAD_VALUE;
755 }
756 audio_port_v7 portV7;
757 audio_populate_audio_port_v7(port, &portV7);
758 RETURN_STATUS_IF_ERROR(getAudioPort(&portV7));
759 return audio_populate_audio_port(&portV7, port) ? OK : BAD_VALUE;
760}
761
762status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
763 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
764 TIME_CHECK();
765 if (!mModule) return NO_INIT;
766 if (port == nullptr) {
767 return BAD_VALUE;
768 }
769 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
770 ::aidl::android::AudioPortDirection::INPUT;
771 auto aidlPort = VALUE_OR_RETURN_STATUS(
772 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
773 if (aidlPort.ext.getTag() != AudioPortExt::device) {
774 ALOGE("%s: provided port is not a device port (module %s): %s",
775 __func__, mInstance.c_str(), aidlPort.toString().c_str());
776 return BAD_VALUE;
777 }
778 const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
779 // It seems that we don't have to call HAL since all valid ports have been added either
780 // during initialization, or while handling connection of an external device.
781 auto portsIt = findPort(matchDevice);
782 if (portsIt == mPorts.end()) {
783 ALOGE("%s: device port for device %s is not found in the module %s",
784 __func__, matchDevice.toString().c_str(), mInstance.c_str());
785 return BAD_VALUE;
786 }
787 const int32_t fwkId = aidlPort.id;
788 aidlPort = portsIt->second;
789 aidlPort.id = fwkId;
790 *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
791 aidlPort, isInput));
792 return OK;
793}
794
795status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
796 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
797 TIME_CHECK();
798 if (!mModule) return NO_INIT;
799 if (config == nullptr) {
800 return BAD_VALUE;
801 }
802 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
803 config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
804 AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
805 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
806 *config, isInput, 0 /*portId*/));
807 AudioPortConfig portConfig;
808 bool created = false;
Mikhail Naganovecfafb72023-03-29 10:06:15 -0700809 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
810 requestedPortConfig, std::set<int32_t>(), &portConfig, &created));
Shunkai Yao51202502022-12-12 06:11:46 +0000811 return OK;
812}
813
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800814MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
815 if (mMicrophones.status == Microphones::Status::UNKNOWN) {
816 TIME_CHECK();
817 std::vector<MicrophoneInfo> aidlInfo;
818 status_t status = statusTFromBinderStatus(mModule->getMicrophones(&aidlInfo));
819 if (status == OK) {
820 mMicrophones.status = Microphones::Status::QUERIED;
821 mMicrophones.info = std::move(aidlInfo);
822 } else if (status == INVALID_OPERATION) {
823 mMicrophones.status = Microphones::Status::NOT_SUPPORTED;
824 } else {
825 ALOGE("%s: Unexpected status from 'IModule.getMicrophones': %d", __func__, status);
826 return {};
827 }
828 }
829 if (mMicrophones.status == Microphones::Status::QUERIED) {
830 return &mMicrophones.info;
831 }
832 return {}; // NOT_SUPPORTED
833}
834
Shunkai Yao51202502022-12-12 06:11:46 +0000835status_t DeviceHalAidl::getMicrophones(
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800836 std::vector<audio_microphone_characteristic_t>* microphones) {
837 if (!microphones) {
838 return BAD_VALUE;
839 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000840 TIME_CHECK();
841 if (!mModule) return NO_INIT;
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800842 auto staticInfo = getMicrophoneInfo();
843 if (!staticInfo) return INVALID_OPERATION;
844 std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
845 emptyDynamicInfo.reserve(staticInfo->size());
846 std::transform(staticInfo->begin(), staticInfo->end(), std::back_inserter(emptyDynamicInfo),
847 [](const auto& info) { return MicrophoneDynamicInfo{ .id = info.id }; });
848 *microphones = VALUE_OR_RETURN_STATUS(
849 ::aidl::android::convertContainers<std::vector<audio_microphone_characteristic_t>>(
850 *staticInfo, emptyDynamicInfo,
851 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t)
852 );
Shunkai Yao51202502022-12-12 06:11:46 +0000853 return OK;
854}
855
Mikhail Naganov31d46652023-01-10 18:29:25 +0000856status_t DeviceHalAidl::addDeviceEffect(audio_port_handle_t device __unused,
857 sp<EffectHalInterface> effect) {
Shunkai Yao51202502022-12-12 06:11:46 +0000858 if (!effect) {
859 return BAD_VALUE;
860 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000861 TIME_CHECK();
862 if (!mModule) return NO_INIT;
863 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000864 return OK;
865}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000866status_t DeviceHalAidl::removeDeviceEffect(audio_port_handle_t device __unused,
Shunkai Yao51202502022-12-12 06:11:46 +0000867 sp<EffectHalInterface> effect) {
868 if (!effect) {
869 return BAD_VALUE;
870 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000871 TIME_CHECK();
872 if (!mModule) return NO_INIT;
873 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000874 return OK;
875}
876
877status_t DeviceHalAidl::getMmapPolicyInfos(
David Li9cf5e622023-03-21 00:51:10 +0800878 media::audio::common::AudioMMapPolicyType policyType,
879 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000880 TIME_CHECK();
Mikhail Naganovbfbb75b2023-04-21 18:48:16 -0700881 AudioMMapPolicyType mmapPolicyType = VALUE_OR_RETURN_STATUS(
882 cpp2ndk_AudioMMapPolicyType(policyType));
David Li9cf5e622023-03-21 00:51:10 +0800883
884 std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
885
886 if (status_t status = statusTFromBinderStatus(
887 mModule->getMmapPolicyInfos(mmapPolicyType, &mmapPolicyInfos)); status != OK) {
888 return status;
889 }
890
891 *policyInfos = VALUE_OR_RETURN_STATUS(
892 convertContainer<std::vector<media::audio::common::AudioMMapPolicyInfo>>(
893 mmapPolicyInfos, ndk2cpp_AudioMMapPolicyInfo));
Shunkai Yao51202502022-12-12 06:11:46 +0000894 return OK;
895}
896
897int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000898 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800899 int32_t mixerBurstCount = 0;
900 if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
901 return mixerBurstCount;
902 }
903 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000904}
905
906int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000907 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800908 int32_t hardwareBurstMinUsec = 0;
909 if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
910 return hardwareBurstMinUsec;
911 }
912 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000913}
914
915error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000916 TIME_CHECK();
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700917 if (!mModule) return NO_INIT;
918 int32_t aidlHwAvSync;
919 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
920 return VALUE_OR_RETURN_STATUS(
921 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +0000922}
923
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000924status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
925 TIME_CHECK();
926 if (!mModule) return NO_INIT;
927 return mModule->dump(fd, Args(args).args(), args.size());
David Li9cf5e622023-03-21 00:51:10 +0800928}
Shunkai Yao51202502022-12-12 06:11:46 +0000929
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700930int32_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000931 TIME_CHECK();
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700932 if (!mModule) return NO_INIT;
933 if (supports == nullptr) {
934 return BAD_VALUE;
935 }
936 return statusTFromBinderStatus(mModule->supportsVariableLatency(supports));
Shunkai Yao51202502022-12-12 06:11:46 +0000937}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000938
Vlad Popa03bd5bc2023-01-17 16:16:51 +0100939status_t DeviceHalAidl::getSoundDoseInterface(const std::string& module,
940 ::ndk::SpAIBinder* soundDoseBinder) {
941 TIME_CHECK();
942 if (!mModule) return NO_INIT;
943 if (mSoundDose == nullptr) {
944 ndk::ScopedAStatus status = mModule->getSoundDose(&mSoundDose);
945 if (!status.isOk()) {
946 ALOGE("%s failed to return the sound dose interface for module %s: %s",
947 __func__,
948 module.c_str(),
949 status.getDescription().c_str());
950 return BAD_VALUE;
951 }
952 }
953 *soundDoseBinder = mSoundDose->asBinder();
954 ALOGI("%s using audio AIDL HAL sound dose interface", __func__);
955
956 return OK;
957}
958
jiabinc0048632023-04-27 22:04:31 +0000959status_t DeviceHalAidl::prepareToDisconnectExternalDevice(const struct audio_port_v7* port) {
960 // There is not AIDL API defined for `prepareToDisconnectExternalDevice`.
961 // Call `setConnectedState` instead.
962 // TODO(b/279824103): call prepareToDisconnectExternalDevice when it is added.
963 const status_t status = setConnectedState(port, false /*connected*/);
964 if (status == NO_ERROR) {
965 mDeviceDisconnectionNotified.insert(port->id);
966 }
967 return status;
968}
969
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700970status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
971 TIME_CHECK();
972 if (!mModule) return NO_INIT;
973 if (port == nullptr) {
974 return BAD_VALUE;
975 }
jiabinc0048632023-04-27 22:04:31 +0000976 if (!connected && mDeviceDisconnectionNotified.erase(port->id) > 0) {
977 // For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
978 // and then call `setConnectedState`. However, there is no API for
979 // `prepareToDisconnectExternalDevice` yet. In that case, `setConnectedState` will be
980 // called when calling `prepareToDisconnectExternalDevice`. Do not call to the HAL if
981 // previous call is successful. Also remove the cache here to avoid a large cache after
982 // a long run.
983 return NO_ERROR;
984 }
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -0700985 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
986 ::aidl::android::AudioPortDirection::INPUT;
987 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
988 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
989 if (aidlPort.ext.getTag() != AudioPortExt::device) {
990 ALOGE("%s: provided port is not a device port (module %s): %s",
991 __func__, mInstance.c_str(), aidlPort.toString().c_str());
992 return BAD_VALUE;
993 }
994 if (connected) {
995 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
996 // Reset the device address to find the "template" port.
997 matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
998 auto portsIt = findPort(matchDevice);
999 if (portsIt == mPorts.end()) {
1000 ALOGW("%s: device port for device %s is not found in the module %s",
1001 __func__, matchDevice.toString().c_str(), mInstance.c_str());
1002 return BAD_VALUE;
1003 }
1004 // Use the ID of the "template" port, use all the information from the provided port.
1005 aidlPort.id = portsIt->first;
1006 AudioPort connectedPort;
1007 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
1008 aidlPort, &connectedPort)));
1009 const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
1010 LOG_ALWAYS_FATAL_IF(!inserted,
1011 "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
1012 __func__, mInstance.c_str(), connectedPort.toString().c_str(),
1013 it->second.toString().c_str());
1014 } else { // !connected
1015 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
1016 auto portsIt = findPort(matchDevice);
1017 if (portsIt == mPorts.end()) {
1018 ALOGW("%s: device port for device %s is not found in the module %s",
1019 __func__, matchDevice.toString().c_str(), mInstance.c_str());
1020 return BAD_VALUE;
1021 }
1022 // Any streams opened on the external device must be closed by this time,
1023 // thus we can clean up patches and port configs that were created for them.
1024 resetUnusedPatchesAndPortConfigs();
1025 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
1026 portsIt->second.id)));
1027 mPorts.erase(portsIt);
1028 }
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001029 return updateRoutes();
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001030}
1031
1032status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
1033 TIME_CHECK();
1034 if (!mModule) return NO_INIT;
1035 ModuleDebug debug{ .simulateDeviceConnections = enabled };
1036 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
1037 // This is important to log as it affects HAL behavior.
1038 if (status == OK) {
1039 ALOGI("%s: set enabled: %d", __func__, enabled);
1040 } else {
1041 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
1042 }
1043 return status;
1044}
1045
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001046bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
1047 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1048 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1049}
1050
1051bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
1052 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
1053 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1054 return p.portId == mDefaultInputPortId;
1055 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1056 return p.portId == mDefaultOutputPortId;
1057 }
1058 return p.ext.get<AudioPortExt::Tag::device>().device == device;
1059}
1060
David Lia8f1e582023-03-30 21:08:06 +08001061status_t DeviceHalAidl::createOrUpdatePortConfig(
1062 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool* created) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001063 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001064 AudioPortConfig appliedPortConfig;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001065 bool applied = false;
1066 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001067 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001068 if (!applied) {
1069 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001070 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001071 if (!applied) {
1072 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001073 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001074 return NO_INIT;
1075 }
1076 }
David Lia8f1e582023-03-30 21:08:06 +08001077
1078 int32_t id = appliedPortConfig.id;
1079 if (requestedPortConfig.id != 0 && requestedPortConfig.id != id) {
1080 LOG_ALWAYS_FATAL("%s: requested port config id %d changed to %d", __func__,
1081 requestedPortConfig.id, id);
1082 }
1083
1084 auto [it, inserted] = mPortConfigs.insert_or_assign(std::move(id),
1085 std::move(appliedPortConfig));
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001086 *result = it;
David Lia8f1e582023-03-30 21:08:06 +08001087 *created = inserted;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001088 return OK;
1089}
1090
1091status_t DeviceHalAidl::findOrCreatePatch(
1092 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
1093 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
1094 requestedPatch.sourcePortConfigIds.end());
1095 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
1096 requestedPatch.sinkPortConfigIds.end());
1097 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
1098}
1099
1100status_t DeviceHalAidl::findOrCreatePatch(
1101 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
1102 AudioPatch* patch, bool* created) {
1103 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
1104 if (patchIt == mPatches.end()) {
1105 TIME_CHECK();
1106 AudioPatch requestedPatch, appliedPatch;
1107 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
1108 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
1109 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
1110 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
1111 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
1112 requestedPatch, &appliedPatch)));
1113 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
1114 *created = true;
1115 } else {
1116 *created = false;
1117 }
1118 *patch = patchIt->second;
1119 return OK;
1120}
1121
jiabin2248fa12023-04-27 22:04:16 +00001122status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device, const AudioConfig* config,
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001123 AudioPortConfig* portConfig, bool* created) {
1124 auto portConfigIt = findPortConfig(device);
1125 if (portConfigIt == mPortConfigs.end()) {
1126 auto portsIt = findPort(device);
1127 if (portsIt == mPorts.end()) {
1128 ALOGE("%s: device port for device %s is not found in the module %s",
1129 __func__, device.toString().c_str(), mInstance.c_str());
1130 return BAD_VALUE;
1131 }
1132 AudioPortConfig requestedPortConfig;
1133 requestedPortConfig.portId = portsIt->first;
jiabin2248fa12023-04-27 22:04:16 +00001134 if (config != nullptr) {
1135 setPortConfigFromConfig(&requestedPortConfig, *config);
1136 }
David Lia8f1e582023-03-30 21:08:06 +08001137 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1138 created));
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001139 } else {
1140 *created = false;
1141 }
1142 *portConfig = portConfigIt->second;
1143 return OK;
1144}
1145
1146status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001147 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001148 AudioSource source, const std::set<int32_t>& destinationPortIds,
1149 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001150 // These flags get removed one by one in this order when retrying port finding.
1151 static const std::vector<AudioInputFlags> kOptionalInputFlags{
1152 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001153 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001154 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001155 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
1156 AudioIoFlags matchFlags = flags.value();
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001157 auto portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001158 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
1159 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
1160 if (!isBitPositionFlagSet(
1161 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
1162 ++optionalInputFlagsIt;
1163 continue;
1164 }
1165 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
1166 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001167 portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001168 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
1169 "retried with flags %s", __func__, config.toString().c_str(),
1170 flags.value().toString().c_str(), mInstance.c_str(),
1171 matchFlags.toString().c_str());
1172 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001173 if (portsIt == mPorts.end()) {
1174 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001175 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001176 mInstance.c_str());
1177 return BAD_VALUE;
1178 }
1179 AudioPortConfig requestedPortConfig;
1180 requestedPortConfig.portId = portsIt->first;
1181 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001182 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001183 if (matchFlags.getTag() == AudioIoFlags::Tag::input
1184 && source != AudioSource::SYS_RESERVED_INVALID) {
1185 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
1186 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
1187 }
David Lia8f1e582023-03-30 21:08:06 +08001188 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1189 created));
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001190 } else if (!flags.has_value()) {
1191 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
1192 "and was not created as flags are not specified",
1193 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
1194 return BAD_VALUE;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001195 } else {
David Lia8f1e582023-03-30 21:08:06 +08001196 AudioPortConfig requestedPortConfig = portConfigIt->second;
1197 if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
1198 AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
1199 if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
1200 source != AudioSource::SYS_RESERVED_INVALID) {
1201 mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
1202 }
1203 }
1204
1205 if (requestedPortConfig != portConfigIt->second) {
1206 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1207 created));
1208 } else {
1209 *created = false;
1210 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001211 }
1212 *portConfig = portConfigIt->second;
1213 return OK;
1214}
1215
1216status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001217 const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
1218 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001219 using Tag = AudioPortExt::Tag;
1220 if (requestedPortConfig.ext.getTag() == Tag::mix) {
1221 if (const auto& p = requestedPortConfig;
1222 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001223 !p.format.has_value()) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001224 ALOGW("%s: provided mix port config is not fully specified: %s",
1225 __func__, p.toString().c_str());
1226 return BAD_VALUE;
1227 }
1228 AudioConfig config;
1229 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001230 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
1231 AudioPortMixExtUseCase::Tag::source ?
1232 requestedPortConfig.ext.get<Tag::mix>().usecase.
1233 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001234 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001235 requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
1236 portConfig, created);
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001237 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
1238 return findOrCreatePortConfig(
jiabin2248fa12023-04-27 22:04:16 +00001239 requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
1240 portConfig, created);
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001241 }
1242 ALOGW("%s: unsupported audio port config: %s",
1243 __func__, requestedPortConfig.toString().c_str());
1244 return BAD_VALUE;
1245}
1246
1247DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
1248 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
1249 return std::find_if(mPatches.begin(), mPatches.end(),
1250 [&](const auto& pair) {
1251 const auto& p = pair.second;
1252 std::set<int32_t> patchSrcs(
1253 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
1254 std::set<int32_t> patchSinks(
1255 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
1256 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
1257}
1258
1259DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001260 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1261 return mPorts.find(mDefaultInputPortId);
1262 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1263 return mPorts.find(mDefaultOutputPortId);
1264 }
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001265 return std::find_if(mPorts.begin(), mPorts.end(),
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001266 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001267}
1268
1269DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001270 const AudioConfig& config, const AudioIoFlags& flags,
1271 const std::set<int32_t>& destinationPortIds) {
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001272 auto belongsToProfile = [&config](const AudioProfile& prof) {
1273 return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
1274 (config.base.channelMask.getTag() == AudioChannelLayout::none ||
1275 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
1276 config.base.channelMask) != prof.channelMasks.end()) &&
1277 (config.base.sampleRate == 0 ||
1278 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
1279 config.base.sampleRate) != prof.sampleRates.end());
1280 };
jiabin2248fa12023-04-27 22:04:16 +00001281 static const std::vector<AudioOutputFlags> kOptionalOutputFlags{AudioOutputFlags::BIT_PERFECT};
1282 int optionalFlags = 0;
1283 auto flagMatches = [&flags, &optionalFlags](const AudioIoFlags& portFlags) {
1284 // Ports should be able to match if the optional flags are not requested.
1285 return portFlags == flags ||
1286 (portFlags.getTag() == AudioIoFlags::Tag::output &&
1287 AudioIoFlags::make<AudioIoFlags::Tag::output>(
1288 portFlags.get<AudioIoFlags::Tag::output>() &
1289 ~optionalFlags) == flags);
1290 };
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001291 auto matcher = [&](const auto& pair) {
1292 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001293 return p.ext.getTag() == AudioPortExt::Tag::mix &&
jiabin2248fa12023-04-27 22:04:16 +00001294 flagMatches(p.flags) &&
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001295 (destinationPortIds.empty() ||
1296 std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
1297 [&](const int32_t destId) { return mRoutingMatrix.count(
1298 std::make_pair(p.id, destId)) != 0; })) &&
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001299 (p.profiles.empty() ||
1300 std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
1301 p.profiles.end()); };
jiabin2248fa12023-04-27 22:04:16 +00001302 auto result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1303 if (result == mPorts.end() && flags.getTag() == AudioIoFlags::Tag::output) {
1304 auto optionalOutputFlagsIt = kOptionalOutputFlags.begin();
1305 while (result == mPorts.end() && optionalOutputFlagsIt != kOptionalOutputFlags.end()) {
1306 if (isBitPositionFlagSet(
1307 flags.get<AudioIoFlags::Tag::output>(), *optionalOutputFlagsIt)) {
1308 // If the flag is set by the request, it must be matched.
1309 ++optionalOutputFlagsIt;
1310 continue;
1311 }
1312 optionalFlags |= makeBitPositionFlagMask(*optionalOutputFlagsIt++);
1313 result = std::find_if(mPorts.begin(), mPorts.end(), matcher);
1314 ALOGI("%s: port for config %s, flags %s was not found in the module %s, "
1315 "retried with excluding optional flags %#x", __func__, config.toString().c_str(),
1316 flags.toString().c_str(), mInstance.c_str(), optionalFlags);
1317 }
1318 }
1319 return result;
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001320}
1321
1322DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001323 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001324 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001325}
1326
1327DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001328 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001329 using Tag = AudioPortExt::Tag;
1330 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
1331 [&](const auto& pair) {
1332 const auto& p = pair.second;
1333 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
1334 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
1335 !p.format.has_value() || !p.flags.has_value(),
1336 "%s: stored mix port config is not fully specified: %s",
1337 __func__, p.toString().c_str());
1338 return p.ext.getTag() == Tag::mix &&
1339 isConfigEqualToPortConfig(config, p) &&
Mikhail Naganov8bd806e2023-01-30 12:33:18 -08001340 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001341 p.ext.template get<Tag::mix>().handle == ioHandle; });
1342}
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001343
Mikhail Naganovf56ce782023-01-25 11:29:11 -08001344void DeviceHalAidl::resetPatch(int32_t patchId) {
1345 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1346 mPatches.erase(it);
1347 TIME_CHECK();
1348 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1349 ALOGE("%s: error while resetting patch %d: %s",
1350 __func__, patchId, status.getDescription().c_str());
1351 }
1352 return;
1353 }
1354 ALOGE("%s: patch id %d not found", __func__, patchId);
1355}
1356
1357void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1358 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1359 mPortConfigs.erase(it);
1360 TIME_CHECK();
1361 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1362 !status.isOk()) {
1363 ALOGE("%s: error while resetting port config %d: %s",
1364 __func__, portConfigId, status.getDescription().c_str());
1365 }
1366 return;
1367 }
1368 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1369}
1370
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001371void DeviceHalAidl::resetUnusedPatches() {
1372 // Since patches can be created independently of streams via 'createAudioPatch',
1373 // here we only clean up patches for released streams.
1374 for (auto it = mStreams.begin(); it != mStreams.end(); ) {
1375 if (auto streamSp = it->first.promote(); streamSp) {
1376 ++it;
1377 } else {
1378 resetPatch(it->second);
1379 it = mStreams.erase(it);
1380 }
1381 }
1382}
1383
1384void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
1385 resetUnusedPatches();
1386 resetUnusedPortConfigs();
1387}
1388
1389void DeviceHalAidl::resetUnusedPortConfigs() {
1390 // The assumption is that port configs are used to create patches
1391 // (or to open streams, but that involves creation of patches, too). Thus,
1392 // orphaned port configs can and should be reset.
1393 std::set<int32_t> portConfigIds;
1394 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
1395 std::inserter(portConfigIds, portConfigIds.end()),
1396 [](const auto& pcPair) { return pcPair.first; });
1397 for (const auto& p : mPatches) {
1398 for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
1399 for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
1400 }
jiabin2248fa12023-04-27 22:04:16 +00001401 for (int32_t id : mInitialPortConfigIds) {
1402 portConfigIds.erase(id);
1403 }
Mikhail Naganovb1ddbb02023-03-15 17:06:59 -07001404 for (int32_t id : portConfigIds) resetPortConfig(id);
1405}
1406
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001407status_t DeviceHalAidl::updateRoutes() {
1408 TIME_CHECK();
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001409 RETURN_STATUS_IF_ERROR(
Mikhail Naganov2d814892023-04-24 13:06:04 -07001410 statusTFromBinderStatus(mModule->getAudioRoutes(&mRoutes)));
1411 ALOGW_IF(mRoutes.empty(), "%s: module %s returned an empty list of audio routes",
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001412 __func__, mInstance.c_str());
1413 mRoutingMatrix.clear();
Mikhail Naganov2d814892023-04-24 13:06:04 -07001414 for (const auto& r : mRoutes) {
Mikhail Naganovecfafb72023-03-29 10:06:15 -07001415 for (auto portId : r.sourcePortIds) {
1416 mRoutingMatrix.emplace(r.sinkPortId, portId);
1417 mRoutingMatrix.emplace(portId, r.sinkPortId);
1418 }
1419 }
1420 return OK;
1421}
1422
Mikhail Naganovb0c55252023-02-08 16:59:41 -08001423void DeviceHalAidl::clearCallbacks(void* cookie) {
1424 std::lock_guard l(mLock);
1425 mCallbacks.erase(cookie);
1426}
1427
1428sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1429 return getCallbackImpl(cookie, &Callbacks::out);
1430}
1431
1432void DeviceHalAidl::setStreamOutCallback(
1433 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1434 setCallbackImpl(cookie, &Callbacks::out, cb);
1435}
1436
1437sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1438 void* cookie) {
1439 return getCallbackImpl(cookie, &Callbacks::event);
1440}
1441
1442void DeviceHalAidl::setStreamOutEventCallback(
1443 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1444 setCallbackImpl(cookie, &Callbacks::event, cb);
1445}
1446
1447sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1448 void* cookie) {
1449 return getCallbackImpl(cookie, &Callbacks::latency);
1450}
1451
1452void DeviceHalAidl::setStreamOutLatencyModeCallback(
1453 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1454 setCallbackImpl(cookie, &Callbacks::latency, cb);
1455}
1456
1457template<class C>
1458sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1459 std::lock_guard l(mLock);
1460 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1461 return ((it->second).*field).promote();
1462 }
1463 return nullptr;
1464}
1465template<class C>
1466void DeviceHalAidl::setCallbackImpl(
1467 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1468 std::lock_guard l(mLock);
1469 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1470 (it->second).*field = cb;
1471 }
1472}
1473
Mikhail Naganov31d46652023-01-10 18:29:25 +00001474} // namespace android