blob: ebffaff0547692295f71a778a8e8e796a0965c90 [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;
107 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); });
163 std::vector<AudioPatch> patches;
164 RETURN_STATUS_IF_ERROR(
165 statusTFromBinderStatus(mModule->getAudioPatches(&patches))); // OK if empty
166 std::transform(patches.begin(), patches.end(),
167 std::inserter(mPatches, mPatches.end()),
168 [](const auto& p) { return std::make_pair(p.id, p); });
Shunkai Yao51202502022-12-12 06:11:46 +0000169 return OK;
170}
171
172status_t DeviceHalAidl::setVoiceVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000173 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000174 if (!mModule) return NO_INIT;
175 std::shared_ptr<ITelephony> telephony;
176 if (ndk::ScopedAStatus status = mModule->getTelephony(&telephony);
177 status.isOk() && telephony != nullptr) {
178 ITelephony::TelecomConfig inConfig{ .voiceVolume = Float{volume} }, outConfig;
179 RETURN_STATUS_IF_ERROR(
180 statusTFromBinderStatus(telephony->setTelecomConfig(inConfig, &outConfig)));
181 ALOGW_IF(outConfig.voiceVolume.has_value() && volume != outConfig.voiceVolume.value().value,
182 "%s: the resulting voice volume %f is not the same as requested %f",
183 __func__, outConfig.voiceVolume.value().value, volume);
184 }
185 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +0000186}
187
188status_t DeviceHalAidl::setMasterVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000189 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000190 if (!mModule) return NO_INIT;
191 return statusTFromBinderStatus(mModule->setMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000192}
193
194status_t DeviceHalAidl::getMasterVolume(float *volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000195 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000196 if (!mModule) return NO_INIT;
197 return statusTFromBinderStatus(mModule->getMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000198}
199
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000200status_t DeviceHalAidl::setMode(audio_mode_t mode) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000201 TIME_CHECK();
202 if (!mModule) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000203 AudioMode audioMode = VALUE_OR_FATAL(::aidl::android::legacy2aidl_audio_mode_t_AudioMode(mode));
204 std::shared_ptr<ITelephony> telephony;
205 if (ndk::ScopedAStatus status = mModule->getTelephony(&telephony);
206 status.isOk() && telephony != nullptr) {
207 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(telephony->switchAudioMode(audioMode)));
208 }
209 return statusTFromBinderStatus(mModule->updateAudioMode(audioMode));
Shunkai Yao51202502022-12-12 06:11:46 +0000210}
211
212status_t DeviceHalAidl::setMicMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000213 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000214 if (!mModule) return NO_INIT;
215 return statusTFromBinderStatus(mModule->setMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000216}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000217
Shunkai Yao51202502022-12-12 06:11:46 +0000218status_t DeviceHalAidl::getMicMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000219 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000220 if (!mModule) return NO_INIT;
221 return statusTFromBinderStatus(mModule->getMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000222}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000223
Shunkai Yao51202502022-12-12 06:11:46 +0000224status_t DeviceHalAidl::setMasterMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000225 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000226 if (!mModule) return NO_INIT;
227 return statusTFromBinderStatus(mModule->setMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000228}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000229
Shunkai Yao51202502022-12-12 06:11:46 +0000230status_t DeviceHalAidl::getMasterMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000231 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000232 if (!mModule) return NO_INIT;
233 return statusTFromBinderStatus(mModule->getMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000234}
235
Mikhail Naganov31d46652023-01-10 18:29:25 +0000236status_t DeviceHalAidl::setParameters(const String8& kvPairs __unused) {
237 TIME_CHECK();
238 if (!mModule) return NO_INIT;
239 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000240 return OK;
241}
242
Mikhail Naganov31d46652023-01-10 18:29:25 +0000243status_t DeviceHalAidl::getParameters(const String8& keys __unused, String8 *values) {
244 TIME_CHECK();
245 values->clear();
246 if (!mModule) return NO_INIT;
247 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000248 return OK;
249}
250
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800251namespace {
252
253class Cleanup {
254 public:
255 typedef void (DeviceHalAidl::*Cleaner)(int32_t);
256
257 Cleanup(DeviceHalAidl* device, Cleaner cleaner, int32_t id) :
258 mDevice(device), mCleaner(cleaner), mId(id) {}
259 ~Cleanup() { clean(); }
260 void clean() {
261 if (mDevice != nullptr) (mDevice->*mCleaner)(mId);
262 disarm();
263 }
264 void disarm() { mDevice = nullptr; }
265
266 private:
267 DeviceHalAidl* mDevice;
268 const Cleaner mCleaner;
269 const int32_t mId;
270};
271
272} // namespace
273
274// Since the order of container elements destruction is unspecified,
275// ensure that cleanups are performed from the most recent one and upwards.
276// This is the same as if there were individual Cleanup instances on the stack,
277// however the bonus is that we can disarm all of them with just one statement.
278class DeviceHalAidl::Cleanups : public std::forward_list<Cleanup> {
279 public:
280 ~Cleanups() { for (auto& c : *this) c.clean(); }
281 void disarmAll() { for (auto& c : *this) c.disarm(); }
282};
283
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800284status_t DeviceHalAidl::getInputBufferSize(const struct audio_config* config, size_t* size) {
285 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
286 if (size == nullptr) return BAD_VALUE;
287 TIME_CHECK();
288 if (!mModule) return NO_INIT;
289 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
290 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
291 AudioDevice aidlDevice;
292 aidlDevice.type.type = AudioDeviceType::IN_DEFAULT;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800293 AudioSource aidlSource = AudioSource::DEFAULT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800294 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
295 AudioPortConfig mixPortConfig;
296 Cleanups cleanups;
297 audio_config writableConfig = *config;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700298 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800299 RETURN_STATUS_IF_ERROR(prepareToOpenStream(0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700300 &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800301 *size = aidlConfig.frameCount *
302 getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
303 // Do not disarm cleanups to release temporary port configs.
304 return OK;
305}
306
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800307status_t DeviceHalAidl::prepareToOpenStream(
308 int32_t aidlHandle, const AudioDevice& aidlDevice, const AudioIoFlags& aidlFlags,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800309 AudioSource aidlSource, struct audio_config* config,
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800310 Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700311 AudioPatch* aidlPatch) {
312 ALOGD("%p %s::%s: handle %d, device %s, flags %s, source %s, config %s, mix port config %s",
313 this, getClassName().c_str(), __func__, aidlHandle, aidlDevice.toString().c_str(),
314 aidlFlags.toString().c_str(), toString(aidlSource).c_str(),
315 aidlConfig->toString().c_str(), mixPortConfig->toString().c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800316 const bool isInput = aidlFlags.getTag() == AudioIoFlags::Tag::input;
317 // Find / create AudioPortConfigs for the device port and the mix port,
318 // then find / create a patch between them, and open a stream on the mix port.
319 AudioPortConfig devicePortConfig;
320 bool created = false;
321 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, &devicePortConfig, &created));
322 if (created) {
323 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
324 }
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800325 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*aidlConfig, aidlFlags, aidlHandle, aidlSource,
Mikhail Naganov289468a2023-03-29 10:06:15 -0700326 std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800327 if (created) {
328 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
329 }
330 setConfigFromPortConfig(aidlConfig, *mixPortConfig);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800331 if (isInput) {
332 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700333 {devicePortConfig.id}, {mixPortConfig->id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800334 } else {
335 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700336 {mixPortConfig->id}, {devicePortConfig.id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800337 }
338 if (created) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700339 cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, aidlPatch->id);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800340 }
341 if (aidlConfig->frameCount <= 0) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700342 aidlConfig->frameCount = aidlPatch->minimumStreamBufferSizeFrames;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800343 }
344 *config = VALUE_OR_RETURN_STATUS(
345 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(*aidlConfig, isInput));
346 return OK;
347}
348
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800349namespace {
350
351class StreamCallbackBase {
352 protected:
353 explicit StreamCallbackBase(const sp<CallbackBroker>& broker) : mBroker(broker) {}
354 public:
355 void* getCookie() const { return mCookie; }
356 void setCookie(void* cookie) { mCookie = cookie; }
357 sp<CallbackBroker> getBroker() const {
358 if (void* cookie = mCookie; cookie != nullptr) return mBroker.promote();
359 return nullptr;
360 }
361 private:
362 const wp<CallbackBroker> mBroker;
363 std::atomic<void*> mCookie;
364};
365
366template<class C>
367class StreamCallbackBaseHelper {
368 protected:
369 explicit StreamCallbackBaseHelper(const StreamCallbackBase& base) : mBase(base) {}
370 sp<C> getCb(const sp<CallbackBroker>& broker, void* cookie);
371 using CbRef = const sp<C>&;
372 ndk::ScopedAStatus runCb(const std::function<void(CbRef cb)>& f) {
373 if (auto cb = getCb(mBase.getBroker(), mBase.getCookie()); cb != nullptr) f(cb);
374 return ndk::ScopedAStatus::ok();
375 }
376 private:
377 const StreamCallbackBase& mBase;
378};
379
380template<>
381sp<StreamOutHalInterfaceCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>::getCb(
382 const sp<CallbackBroker>& broker, void* cookie) {
383 if (broker != nullptr) return broker->getStreamOutCallback(cookie);
384 return nullptr;
385}
386
387template<>
388sp<StreamOutHalInterfaceEventCallback>
389StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::getCb(
390 const sp<CallbackBroker>& broker, void* cookie) {
391 if (broker != nullptr) return broker->getStreamOutEventCallback(cookie);
392 return nullptr;
393}
394
395template<>
396sp<StreamOutHalInterfaceLatencyModeCallback>
397StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::getCb(
398 const sp<CallbackBroker>& broker, void* cookie) {
399 if (broker != nullptr) return broker->getStreamOutLatencyModeCallback(cookie);
400 return nullptr;
401}
402
403/*
404Note on the callback ownership.
405
406In the Binder ownership model, the server implementation is kept alive
407as long as there is any client (proxy object) alive. This is done by
408incrementing the refcount of the server-side object by the Binder framework.
409When it detects that the last client is gone, it decrements the refcount back.
410
411Thus, it is not needed to keep any references to StreamCallback on our
412side (after we have sent an instance to the client), because we are
413the server-side. The callback object will be kept alive as long as the HAL server
414holds a strong ref to IStreamCallback proxy.
415*/
416
417class OutputStreamCallbackAidl : public StreamCallbackBase,
418 public StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>,
419 public ::aidl::android::hardware::audio::core::BnStreamCallback {
420 public:
421 explicit OutputStreamCallbackAidl(const sp<CallbackBroker>& broker)
422 : StreamCallbackBase(broker),
423 StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>(
424 *static_cast<StreamCallbackBase*>(this)) {}
425 ndk::ScopedAStatus onTransferReady() override {
426 return runCb([](CbRef cb) { cb->onWriteReady(); });
427 }
428 ndk::ScopedAStatus onError() override {
429 return runCb([](CbRef cb) { cb->onError(); });
430 }
431 ndk::ScopedAStatus onDrainReady() override {
432 return runCb([](CbRef cb) { cb->onDrainReady(); });
433 }
434};
435
436class OutputStreamEventCallbackAidl :
437 public StreamCallbackBase,
438 public StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>,
439 public StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>,
440 public ::aidl::android::hardware::audio::core::BnStreamOutEventCallback {
441 public:
442 explicit OutputStreamEventCallbackAidl(const sp<CallbackBroker>& broker)
443 : StreamCallbackBase(broker),
444 StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>(
445 *static_cast<StreamCallbackBase*>(this)),
446 StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>(
447 *static_cast<StreamCallbackBase*>(this)) {}
448 ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& in_audioMetadata) override {
449 std::basic_string<uint8_t> halMetadata(in_audioMetadata.begin(), in_audioMetadata.end());
450 return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb(
451 [&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); });
452 }
453 ndk::ScopedAStatus onRecommendedLatencyModeChanged(
454 const std::vector<AudioLatencyMode>& in_modes) override {
455 auto halModes = VALUE_OR_FATAL(
456 ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
457 in_modes,
458 ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
459 return StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::runCb(
460 [&halModes](auto cb) { cb->onRecommendedLatencyModeChanged(halModes); });
461 }
462};
463
464} // namespace
465
Mikhail Naganov31d46652023-01-10 18:29:25 +0000466status_t DeviceHalAidl::openOutputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800467 audio_io_handle_t handle, audio_devices_t devices,
468 audio_output_flags_t flags, struct audio_config* config,
469 const char* address,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000470 sp<StreamOutHalInterface>* outStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800471 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000472 if (!outStream || !config) {
473 return BAD_VALUE;
474 }
475 TIME_CHECK();
476 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800477 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
478 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
479 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
480 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, false /*isInput*/));
481 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
482 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
483 int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
484 ::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
485 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
486 AudioPortConfig mixPortConfig;
487 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700488 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800489 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
490 AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700491 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800492 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
493 args.portConfigId = mixPortConfig.id;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800494 const bool isOffload = isBitPositionFlagSet(
495 aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD);
496 std::shared_ptr<OutputStreamCallbackAidl> streamCb;
497 if (isOffload) {
498 streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
499 }
500 auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
501 if (isOffload) {
502 args.offloadInfo = aidlConfig.offloadInfo;
503 args.callback = streamCb;
504 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800505 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800506 args.eventCallback = eventCb;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800507 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
508 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800509 StreamContextAidl context(ret.desc, isOffload);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800510 if (!context.isValid()) {
511 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
512 __func__, ret.desc.toString().c_str());
513 return NO_INIT;
514 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700515 *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800516 std::move(ret.stream), this /*callbackBroker*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700517 mStreams.insert(std::pair(*outStream, aidlPatch.id));
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800518 void* cbCookie = (*outStream).get();
519 {
520 std::lock_guard l(mLock);
521 mCallbacks.emplace(cbCookie, Callbacks{});
522 }
523 if (streamCb) streamCb->setCookie(cbCookie);
524 eventCb->setCookie(cbCookie);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800525 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000526 return OK;
527}
528
Mikhail Naganov31d46652023-01-10 18:29:25 +0000529status_t DeviceHalAidl::openInputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800530 audio_io_handle_t handle, audio_devices_t devices,
531 struct audio_config* config, audio_input_flags_t flags,
532 const char* address, audio_source_t source,
533 audio_devices_t outputDevice, const char* outputDeviceAddress,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000534 sp<StreamInHalInterface>* inStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800535 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000536 if (!inStream || !config) {
537 return BAD_VALUE;
538 }
539 TIME_CHECK();
540 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800541 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
542 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
543 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
544 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
545 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
546 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
547 int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
548 ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
549 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
550 AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
551 ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
552 AudioPortConfig mixPortConfig;
553 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700554 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800555 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700556 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800557 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
558 args.portConfigId = mixPortConfig.id;
559 RecordTrackMetadata aidlTrackMetadata{
560 .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
561 if (outputDevice != AUDIO_DEVICE_NONE) {
562 aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
563 ::aidl::android::legacy2aidl_audio_device_AudioDevice(
564 outputDevice, outputDeviceAddress));
565 }
566 args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
567 args.bufferSizeFrames = aidlConfig.frameCount;
568 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
569 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800570 StreamContextAidl context(ret.desc, false /*isAsynchronous*/);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800571 if (!context.isValid()) {
572 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
573 __func__, ret.desc.toString().c_str());
574 return NO_INIT;
575 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700576 *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800577 std::move(ret.stream), this /*micInfoProvider*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700578 mStreams.insert(std::pair(*inStream, aidlPatch.id));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800579 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000580 return OK;
581}
582
583status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
584 *supportsPatches = true;
585 return OK;
586}
587
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800588status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
589 const struct audio_port_config* sources,
590 unsigned int num_sinks,
591 const struct audio_port_config* sinks,
592 audio_patch_handle_t* patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800593 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000594 TIME_CHECK();
595 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800596 if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
597 sources == nullptr || sinks == nullptr || patch == nullptr) {
598 return BAD_VALUE;
599 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800600 // When the patch handle (*patch) is AUDIO_PATCH_HANDLE_NONE, it means
601 // the framework wants to create a new patch. The handle has to be generated
602 // by the HAL. Since handles generated this way can only be unique within
603 // a HAL module, the framework generates a globally unique handle, and maps
604 // it on the <HAL module, patch handle> pair.
605 // When the patch handle is set, it meant the framework intends to update
606 // an existing patch.
607 //
608 // This behavior corresponds to HAL module behavior, with the only difference
609 // that the HAL module uses `int32_t` for patch IDs. The following assert ensures
610 // that both the framework and the HAL use the same value for "no ID":
611 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
612 int32_t halPatchId = static_cast<int32_t>(*patch);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800613
614 // Upon conversion, mix port configs contain audio configuration, while
615 // device port configs contain device address. This data is used to find
616 // or create HAL configs.
617 std::vector<AudioPortConfig> aidlSources, aidlSinks;
618 for (unsigned int i = 0; i < num_sources; ++i) {
619 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
620 sources[i].role, sources[i].type)) ==
621 ::aidl::android::AudioPortDirection::INPUT;
622 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
623 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
624 sources[i], isInput, 0)));
625 }
626 for (unsigned int i = 0; i < num_sinks; ++i) {
627 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
628 sinks[i].role, sinks[i].type)) ==
629 ::aidl::android::AudioPortDirection::INPUT;
630 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
631 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
632 sinks[i], isInput, 0)));
633 }
634 Cleanups cleanups;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800635 auto existingPatchIt = halPatchId != 0 ? mPatches.find(halPatchId): mPatches.end();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800636 AudioPatch aidlPatch;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800637 if (existingPatchIt != mPatches.end()) {
638 aidlPatch = existingPatchIt->second;
639 aidlPatch.sourcePortConfigIds.clear();
640 aidlPatch.sinkPortConfigIds.clear();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800641 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800642 ALOGD("%s: sources: %s, sinks: %s",
643 __func__, ::android::internal::ToString(aidlSources).c_str(),
644 ::android::internal::ToString(aidlSinks).c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800645 auto fillPortConfigs = [&](
Mikhail Naganov289468a2023-03-29 10:06:15 -0700646 const std::vector<AudioPortConfig>& configs,
647 const std::set<int32_t>& destinationPortIds,
648 std::vector<int32_t>* ids, std::set<int32_t>* portIds) -> status_t {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800649 for (const auto& s : configs) {
650 AudioPortConfig portConfig;
651 bool created = false;
Mikhail Naganov289468a2023-03-29 10:06:15 -0700652 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
653 s, destinationPortIds, &portConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800654 if (created) {
655 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, portConfig.id);
656 }
657 ids->push_back(portConfig.id);
Mikhail Naganov289468a2023-03-29 10:06:15 -0700658 if (portIds != nullptr) {
659 portIds->insert(portConfig.portId);
660 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800661 }
662 return OK;
663 };
Mikhail Naganov289468a2023-03-29 10:06:15 -0700664 // When looking up port configs, the destinationPortId is only used for mix ports.
665 // Thus, we process device port configs first, and look up the destination port ID from them.
666 bool sourceIsDevice = std::any_of(aidlSources.begin(), aidlSources.end(),
667 [](const auto& config) { return config.ext.getTag() == AudioPortExt::device; });
668 const std::vector<AudioPortConfig>& devicePortConfigs =
669 sourceIsDevice ? aidlSources : aidlSinks;
670 std::vector<int32_t>* devicePortConfigIds =
671 sourceIsDevice ? &aidlPatch.sourcePortConfigIds : &aidlPatch.sinkPortConfigIds;
672 const std::vector<AudioPortConfig>& mixPortConfigs =
673 sourceIsDevice ? aidlSinks : aidlSources;
674 std::vector<int32_t>* mixPortConfigIds =
675 sourceIsDevice ? &aidlPatch.sinkPortConfigIds : &aidlPatch.sourcePortConfigIds;
676 std::set<int32_t> devicePortIds;
677 RETURN_STATUS_IF_ERROR(fillPortConfigs(
678 devicePortConfigs, std::set<int32_t>(), devicePortConfigIds, &devicePortIds));
679 RETURN_STATUS_IF_ERROR(fillPortConfigs(
680 mixPortConfigs, devicePortIds, mixPortConfigIds, nullptr));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800681 if (existingPatchIt != mPatches.end()) {
682 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
683 mModule->setAudioPatch(aidlPatch, &aidlPatch)));
684 existingPatchIt->second = aidlPatch;
685 } else {
686 bool created = false;
687 RETURN_STATUS_IF_ERROR(findOrCreatePatch(aidlPatch, &aidlPatch, &created));
688 // Since no cleanup of the patch is needed, 'created' is ignored.
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800689 halPatchId = aidlPatch.id;
690 *patch = static_cast<audio_patch_handle_t>(halPatchId);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800691 }
692 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000693 return OK;
694}
695
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800696status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800697 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000698 TIME_CHECK();
699 if (!mModule) return NO_INIT;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800700 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
701 if (patch == AUDIO_PATCH_HANDLE_NONE) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800702 return BAD_VALUE;
703 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800704 int32_t halPatchId = static_cast<int32_t>(patch);
705 auto patchIt = mPatches.find(halPatchId);
706 if (patchIt == mPatches.end()) {
707 ALOGE("%s: patch with id %d not found", __func__, halPatchId);
708 return BAD_VALUE;
709 }
710 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->resetAudioPatch(halPatchId)));
711 mPatches.erase(patchIt);
Shunkai Yao51202502022-12-12 06:11:46 +0000712 return OK;
713}
714
Mikhail Naganove93a0862023-03-15 17:06:59 -0700715status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
716 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000717 TIME_CHECK();
718 if (!mModule) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700719 if (port == nullptr) {
720 return BAD_VALUE;
721 }
722 audio_port_v7 portV7;
723 audio_populate_audio_port_v7(port, &portV7);
724 RETURN_STATUS_IF_ERROR(getAudioPort(&portV7));
725 return audio_populate_audio_port(&portV7, port) ? OK : BAD_VALUE;
726}
727
728status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
729 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
730 TIME_CHECK();
731 if (!mModule) return NO_INIT;
732 if (port == nullptr) {
733 return BAD_VALUE;
734 }
735 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
736 ::aidl::android::AudioPortDirection::INPUT;
737 auto aidlPort = VALUE_OR_RETURN_STATUS(
738 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
739 if (aidlPort.ext.getTag() != AudioPortExt::device) {
740 ALOGE("%s: provided port is not a device port (module %s): %s",
741 __func__, mInstance.c_str(), aidlPort.toString().c_str());
742 return BAD_VALUE;
743 }
744 const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
745 // It seems that we don't have to call HAL since all valid ports have been added either
746 // during initialization, or while handling connection of an external device.
747 auto portsIt = findPort(matchDevice);
748 if (portsIt == mPorts.end()) {
749 ALOGE("%s: device port for device %s is not found in the module %s",
750 __func__, matchDevice.toString().c_str(), mInstance.c_str());
751 return BAD_VALUE;
752 }
753 const int32_t fwkId = aidlPort.id;
754 aidlPort = portsIt->second;
755 aidlPort.id = fwkId;
756 *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
757 aidlPort, isInput));
758 return OK;
759}
760
761status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
762 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
763 TIME_CHECK();
764 if (!mModule) return NO_INIT;
765 if (config == nullptr) {
766 return BAD_VALUE;
767 }
768 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
769 config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
770 AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
771 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
772 *config, isInput, 0 /*portId*/));
773 AudioPortConfig portConfig;
774 bool created = false;
Mikhail Naganov289468a2023-03-29 10:06:15 -0700775 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
776 requestedPortConfig, std::set<int32_t>(), &portConfig, &created));
Shunkai Yao51202502022-12-12 06:11:46 +0000777 return OK;
778}
779
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800780MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
781 if (mMicrophones.status == Microphones::Status::UNKNOWN) {
782 TIME_CHECK();
783 std::vector<MicrophoneInfo> aidlInfo;
784 status_t status = statusTFromBinderStatus(mModule->getMicrophones(&aidlInfo));
785 if (status == OK) {
786 mMicrophones.status = Microphones::Status::QUERIED;
787 mMicrophones.info = std::move(aidlInfo);
788 } else if (status == INVALID_OPERATION) {
789 mMicrophones.status = Microphones::Status::NOT_SUPPORTED;
790 } else {
791 ALOGE("%s: Unexpected status from 'IModule.getMicrophones': %d", __func__, status);
792 return {};
793 }
794 }
795 if (mMicrophones.status == Microphones::Status::QUERIED) {
796 return &mMicrophones.info;
797 }
798 return {}; // NOT_SUPPORTED
799}
800
Shunkai Yao51202502022-12-12 06:11:46 +0000801status_t DeviceHalAidl::getMicrophones(
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800802 std::vector<audio_microphone_characteristic_t>* microphones) {
803 if (!microphones) {
804 return BAD_VALUE;
805 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000806 TIME_CHECK();
807 if (!mModule) return NO_INIT;
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800808 auto staticInfo = getMicrophoneInfo();
809 if (!staticInfo) return INVALID_OPERATION;
810 std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
811 emptyDynamicInfo.reserve(staticInfo->size());
812 std::transform(staticInfo->begin(), staticInfo->end(), std::back_inserter(emptyDynamicInfo),
813 [](const auto& info) { return MicrophoneDynamicInfo{ .id = info.id }; });
814 *microphones = VALUE_OR_RETURN_STATUS(
815 ::aidl::android::convertContainers<std::vector<audio_microphone_characteristic_t>>(
816 *staticInfo, emptyDynamicInfo,
817 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t)
818 );
Shunkai Yao51202502022-12-12 06:11:46 +0000819 return OK;
820}
821
Mikhail Naganov31d46652023-01-10 18:29:25 +0000822status_t DeviceHalAidl::addDeviceEffect(audio_port_handle_t device __unused,
823 sp<EffectHalInterface> effect) {
Shunkai Yao51202502022-12-12 06:11:46 +0000824 if (!effect) {
825 return BAD_VALUE;
826 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000827 TIME_CHECK();
828 if (!mModule) return NO_INIT;
829 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000830 return OK;
831}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000832status_t DeviceHalAidl::removeDeviceEffect(audio_port_handle_t device __unused,
Shunkai Yao51202502022-12-12 06:11:46 +0000833 sp<EffectHalInterface> effect) {
834 if (!effect) {
835 return BAD_VALUE;
836 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000837 TIME_CHECK();
838 if (!mModule) return NO_INIT;
839 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000840 return OK;
841}
842
843status_t DeviceHalAidl::getMmapPolicyInfos(
David Li9cf5e622023-03-21 00:51:10 +0800844 media::audio::common::AudioMMapPolicyType policyType,
845 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000846 TIME_CHECK();
Mikhail Naganov25bc9a22023-04-21 18:48:16 -0700847 AudioMMapPolicyType mmapPolicyType = VALUE_OR_RETURN_STATUS(
848 cpp2ndk_AudioMMapPolicyType(policyType));
David Li9cf5e622023-03-21 00:51:10 +0800849
850 std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
851
852 if (status_t status = statusTFromBinderStatus(
853 mModule->getMmapPolicyInfos(mmapPolicyType, &mmapPolicyInfos)); status != OK) {
854 return status;
855 }
856
857 *policyInfos = VALUE_OR_RETURN_STATUS(
858 convertContainer<std::vector<media::audio::common::AudioMMapPolicyInfo>>(
859 mmapPolicyInfos, ndk2cpp_AudioMMapPolicyInfo));
Shunkai Yao51202502022-12-12 06:11:46 +0000860 return OK;
861}
862
863int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000864 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800865 int32_t mixerBurstCount = 0;
866 if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
867 return mixerBurstCount;
868 }
869 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000870}
871
872int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000873 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800874 int32_t hardwareBurstMinUsec = 0;
875 if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
876 return hardwareBurstMinUsec;
877 }
878 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000879}
880
881error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000882 TIME_CHECK();
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700883 if (!mModule) return NO_INIT;
884 int32_t aidlHwAvSync;
885 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
886 return VALUE_OR_RETURN_STATUS(
887 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +0000888}
889
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000890status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
891 TIME_CHECK();
892 if (!mModule) return NO_INIT;
893 return mModule->dump(fd, Args(args).args(), args.size());
David Li9cf5e622023-03-21 00:51:10 +0800894}
Shunkai Yao51202502022-12-12 06:11:46 +0000895
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700896int32_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000897 TIME_CHECK();
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700898 if (!mModule) return NO_INIT;
899 if (supports == nullptr) {
900 return BAD_VALUE;
901 }
902 return statusTFromBinderStatus(mModule->supportsVariableLatency(supports));
Shunkai Yao51202502022-12-12 06:11:46 +0000903}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000904
Mikhail Naganove93a0862023-03-15 17:06:59 -0700905status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
906 TIME_CHECK();
907 if (!mModule) return NO_INIT;
908 if (port == nullptr) {
909 return BAD_VALUE;
910 }
911 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
912 ::aidl::android::AudioPortDirection::INPUT;
913 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
914 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
915 if (aidlPort.ext.getTag() != AudioPortExt::device) {
916 ALOGE("%s: provided port is not a device port (module %s): %s",
917 __func__, mInstance.c_str(), aidlPort.toString().c_str());
918 return BAD_VALUE;
919 }
920 if (connected) {
921 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
922 // Reset the device address to find the "template" port.
923 matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
924 auto portsIt = findPort(matchDevice);
925 if (portsIt == mPorts.end()) {
926 ALOGW("%s: device port for device %s is not found in the module %s",
927 __func__, matchDevice.toString().c_str(), mInstance.c_str());
928 return BAD_VALUE;
929 }
930 // Use the ID of the "template" port, use all the information from the provided port.
931 aidlPort.id = portsIt->first;
932 AudioPort connectedPort;
933 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
934 aidlPort, &connectedPort)));
935 const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
936 LOG_ALWAYS_FATAL_IF(!inserted,
937 "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
938 __func__, mInstance.c_str(), connectedPort.toString().c_str(),
939 it->second.toString().c_str());
940 } else { // !connected
941 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
942 auto portsIt = findPort(matchDevice);
943 if (portsIt == mPorts.end()) {
944 ALOGW("%s: device port for device %s is not found in the module %s",
945 __func__, matchDevice.toString().c_str(), mInstance.c_str());
946 return BAD_VALUE;
947 }
948 // Any streams opened on the external device must be closed by this time,
949 // thus we can clean up patches and port configs that were created for them.
950 resetUnusedPatchesAndPortConfigs();
951 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
952 portsIt->second.id)));
953 mPorts.erase(portsIt);
954 }
Mikhail Naganov289468a2023-03-29 10:06:15 -0700955 return updateRoutes();
Mikhail Naganove93a0862023-03-15 17:06:59 -0700956}
957
958status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
959 TIME_CHECK();
960 if (!mModule) return NO_INIT;
961 ModuleDebug debug{ .simulateDeviceConnections = enabled };
962 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
963 // This is important to log as it affects HAL behavior.
964 if (status == OK) {
965 ALOGI("%s: set enabled: %d", __func__, enabled);
966 } else {
967 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
968 }
969 return status;
970}
971
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800972bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
973 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
974 return p.ext.get<AudioPortExt::Tag::device>().device == device;
975}
976
977bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
978 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
979 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
980 return p.portId == mDefaultInputPortId;
981 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
982 return p.portId == mDefaultOutputPortId;
983 }
984 return p.ext.get<AudioPortExt::Tag::device>().device == device;
985}
986
David Lia8675d42023-03-30 21:08:06 +0800987status_t DeviceHalAidl::createOrUpdatePortConfig(
988 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool* created) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800989 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800990 AudioPortConfig appliedPortConfig;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800991 bool applied = false;
992 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800993 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800994 if (!applied) {
995 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800996 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800997 if (!applied) {
998 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800999 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001000 return NO_INIT;
1001 }
1002 }
David Lia8675d42023-03-30 21:08:06 +08001003
1004 int32_t id = appliedPortConfig.id;
1005 if (requestedPortConfig.id != 0 && requestedPortConfig.id != id) {
1006 LOG_ALWAYS_FATAL("%s: requested port config id %d changed to %d", __func__,
1007 requestedPortConfig.id, id);
1008 }
1009
1010 auto [it, inserted] = mPortConfigs.insert_or_assign(std::move(id),
1011 std::move(appliedPortConfig));
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001012 *result = it;
David Lia8675d42023-03-30 21:08:06 +08001013 *created = inserted;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001014 return OK;
1015}
1016
1017status_t DeviceHalAidl::findOrCreatePatch(
1018 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
1019 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
1020 requestedPatch.sourcePortConfigIds.end());
1021 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
1022 requestedPatch.sinkPortConfigIds.end());
1023 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
1024}
1025
1026status_t DeviceHalAidl::findOrCreatePatch(
1027 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
1028 AudioPatch* patch, bool* created) {
1029 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
1030 if (patchIt == mPatches.end()) {
1031 TIME_CHECK();
1032 AudioPatch requestedPatch, appliedPatch;
1033 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
1034 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
1035 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
1036 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
1037 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
1038 requestedPatch, &appliedPatch)));
1039 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
1040 *created = true;
1041 } else {
1042 *created = false;
1043 }
1044 *patch = patchIt->second;
1045 return OK;
1046}
1047
1048status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device,
1049 AudioPortConfig* portConfig, bool* created) {
1050 auto portConfigIt = findPortConfig(device);
1051 if (portConfigIt == mPortConfigs.end()) {
1052 auto portsIt = findPort(device);
1053 if (portsIt == mPorts.end()) {
1054 ALOGE("%s: device port for device %s is not found in the module %s",
1055 __func__, device.toString().c_str(), mInstance.c_str());
1056 return BAD_VALUE;
1057 }
1058 AudioPortConfig requestedPortConfig;
1059 requestedPortConfig.portId = portsIt->first;
David Lia8675d42023-03-30 21:08:06 +08001060 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1061 created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001062 } else {
1063 *created = false;
1064 }
1065 *portConfig = portConfigIt->second;
1066 return OK;
1067}
1068
1069status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001070 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001071 AudioSource source, const std::set<int32_t>& destinationPortIds,
1072 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001073 // These flags get removed one by one in this order when retrying port finding.
1074 static const std::vector<AudioInputFlags> kOptionalInputFlags{
1075 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001076 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001077 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001078 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
1079 AudioIoFlags matchFlags = flags.value();
Mikhail Naganov289468a2023-03-29 10:06:15 -07001080 auto portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001081 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
1082 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
1083 if (!isBitPositionFlagSet(
1084 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
1085 ++optionalInputFlagsIt;
1086 continue;
1087 }
1088 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
1089 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
Mikhail Naganov289468a2023-03-29 10:06:15 -07001090 portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001091 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
1092 "retried with flags %s", __func__, config.toString().c_str(),
1093 flags.value().toString().c_str(), mInstance.c_str(),
1094 matchFlags.toString().c_str());
1095 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001096 if (portsIt == mPorts.end()) {
1097 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001098 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001099 mInstance.c_str());
1100 return BAD_VALUE;
1101 }
1102 AudioPortConfig requestedPortConfig;
1103 requestedPortConfig.portId = portsIt->first;
1104 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001105 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001106 if (matchFlags.getTag() == AudioIoFlags::Tag::input
1107 && source != AudioSource::SYS_RESERVED_INVALID) {
1108 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
1109 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
1110 }
David Lia8675d42023-03-30 21:08:06 +08001111 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1112 created));
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001113 } else if (!flags.has_value()) {
1114 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
1115 "and was not created as flags are not specified",
1116 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
1117 return BAD_VALUE;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001118 } else {
David Lia8675d42023-03-30 21:08:06 +08001119 AudioPortConfig requestedPortConfig = portConfigIt->second;
1120 if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
1121 AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
1122 if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
1123 source != AudioSource::SYS_RESERVED_INVALID) {
1124 mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
1125 }
1126 }
1127
1128 if (requestedPortConfig != portConfigIt->second) {
1129 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1130 created));
1131 } else {
1132 *created = false;
1133 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001134 }
1135 *portConfig = portConfigIt->second;
1136 return OK;
1137}
1138
1139status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001140 const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
1141 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001142 using Tag = AudioPortExt::Tag;
1143 if (requestedPortConfig.ext.getTag() == Tag::mix) {
1144 if (const auto& p = requestedPortConfig;
1145 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001146 !p.format.has_value()) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001147 ALOGW("%s: provided mix port config is not fully specified: %s",
1148 __func__, p.toString().c_str());
1149 return BAD_VALUE;
1150 }
1151 AudioConfig config;
1152 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001153 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
1154 AudioPortMixExtUseCase::Tag::source ?
1155 requestedPortConfig.ext.get<Tag::mix>().usecase.
1156 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001157 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001158 requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
1159 portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001160 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
1161 return findOrCreatePortConfig(
1162 requestedPortConfig.ext.get<Tag::device>().device, portConfig, created);
1163 }
1164 ALOGW("%s: unsupported audio port config: %s",
1165 __func__, requestedPortConfig.toString().c_str());
1166 return BAD_VALUE;
1167}
1168
1169DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
1170 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
1171 return std::find_if(mPatches.begin(), mPatches.end(),
1172 [&](const auto& pair) {
1173 const auto& p = pair.second;
1174 std::set<int32_t> patchSrcs(
1175 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
1176 std::set<int32_t> patchSinks(
1177 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
1178 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
1179}
1180
1181DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001182 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1183 return mPorts.find(mDefaultInputPortId);
1184 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1185 return mPorts.find(mDefaultOutputPortId);
1186 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001187 return std::find_if(mPorts.begin(), mPorts.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001188 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001189}
1190
Mikhail Naganov289468a2023-03-29 10:06:15 -07001191
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001192DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001193 const AudioConfig& config, const AudioIoFlags& flags,
1194 const std::set<int32_t>& destinationPortIds) {
Mikhail Naganove93a0862023-03-15 17:06:59 -07001195 auto belongsToProfile = [&config](const AudioProfile& prof) {
1196 return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
1197 (config.base.channelMask.getTag() == AudioChannelLayout::none ||
1198 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
1199 config.base.channelMask) != prof.channelMasks.end()) &&
1200 (config.base.sampleRate == 0 ||
1201 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
1202 config.base.sampleRate) != prof.sampleRates.end());
1203 };
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001204 auto matcher = [&](const auto& pair) {
1205 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001206 return p.ext.getTag() == AudioPortExt::Tag::mix &&
1207 p.flags == flags &&
Mikhail Naganov289468a2023-03-29 10:06:15 -07001208 (destinationPortIds.empty() ||
1209 std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
1210 [&](const int32_t destId) { return mRoutingMatrix.count(
1211 std::make_pair(p.id, destId)) != 0; })) &&
Mikhail Naganove93a0862023-03-15 17:06:59 -07001212 (p.profiles.empty() ||
1213 std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
1214 p.profiles.end()); };
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001215 return std::find_if(mPorts.begin(), mPorts.end(), matcher);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001216}
1217
1218DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001219 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001220 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001221}
1222
1223DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001224 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001225 using Tag = AudioPortExt::Tag;
1226 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
1227 [&](const auto& pair) {
1228 const auto& p = pair.second;
1229 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
1230 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
1231 !p.format.has_value() || !p.flags.has_value(),
1232 "%s: stored mix port config is not fully specified: %s",
1233 __func__, p.toString().c_str());
1234 return p.ext.getTag() == Tag::mix &&
1235 isConfigEqualToPortConfig(config, p) &&
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001236 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001237 p.ext.template get<Tag::mix>().handle == ioHandle; });
1238}
Mikhail Naganove93a0862023-03-15 17:06:59 -07001239
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001240void DeviceHalAidl::resetPatch(int32_t patchId) {
1241 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1242 mPatches.erase(it);
1243 TIME_CHECK();
1244 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1245 ALOGE("%s: error while resetting patch %d: %s",
1246 __func__, patchId, status.getDescription().c_str());
1247 }
1248 return;
1249 }
1250 ALOGE("%s: patch id %d not found", __func__, patchId);
1251}
1252
1253void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1254 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1255 mPortConfigs.erase(it);
1256 TIME_CHECK();
1257 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1258 !status.isOk()) {
1259 ALOGE("%s: error while resetting port config %d: %s",
1260 __func__, portConfigId, status.getDescription().c_str());
1261 }
1262 return;
1263 }
1264 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1265}
1266
Mikhail Naganove93a0862023-03-15 17:06:59 -07001267void DeviceHalAidl::resetUnusedPatches() {
1268 // Since patches can be created independently of streams via 'createAudioPatch',
1269 // here we only clean up patches for released streams.
1270 for (auto it = mStreams.begin(); it != mStreams.end(); ) {
1271 if (auto streamSp = it->first.promote(); streamSp) {
1272 ++it;
1273 } else {
1274 resetPatch(it->second);
1275 it = mStreams.erase(it);
1276 }
1277 }
1278}
1279
1280void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
1281 resetUnusedPatches();
1282 resetUnusedPortConfigs();
1283}
1284
1285void DeviceHalAidl::resetUnusedPortConfigs() {
1286 // The assumption is that port configs are used to create patches
1287 // (or to open streams, but that involves creation of patches, too). Thus,
1288 // orphaned port configs can and should be reset.
1289 std::set<int32_t> portConfigIds;
1290 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
1291 std::inserter(portConfigIds, portConfigIds.end()),
1292 [](const auto& pcPair) { return pcPair.first; });
1293 for (const auto& p : mPatches) {
1294 for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
1295 for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
1296 }
1297 for (int32_t id : portConfigIds) resetPortConfig(id);
1298}
1299
Mikhail Naganov289468a2023-03-29 10:06:15 -07001300status_t DeviceHalAidl::updateRoutes() {
1301 TIME_CHECK();
Mikhail Naganov289468a2023-03-29 10:06:15 -07001302 RETURN_STATUS_IF_ERROR(
Mikhail Naganovf83b9742023-04-24 13:06:04 -07001303 statusTFromBinderStatus(mModule->getAudioRoutes(&mRoutes)));
1304 ALOGW_IF(mRoutes.empty(), "%s: module %s returned an empty list of audio routes",
Mikhail Naganov289468a2023-03-29 10:06:15 -07001305 __func__, mInstance.c_str());
1306 mRoutingMatrix.clear();
Mikhail Naganovf83b9742023-04-24 13:06:04 -07001307 for (const auto& r : mRoutes) {
Mikhail Naganov289468a2023-03-29 10:06:15 -07001308 for (auto portId : r.sourcePortIds) {
1309 mRoutingMatrix.emplace(r.sinkPortId, portId);
1310 mRoutingMatrix.emplace(portId, r.sinkPortId);
1311 }
1312 }
1313 return OK;
1314}
1315
Mikhail Naganovdfd594e2023-02-08 16:59:41 -08001316void DeviceHalAidl::clearCallbacks(void* cookie) {
1317 std::lock_guard l(mLock);
1318 mCallbacks.erase(cookie);
1319}
1320
1321sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1322 return getCallbackImpl(cookie, &Callbacks::out);
1323}
1324
1325void DeviceHalAidl::setStreamOutCallback(
1326 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1327 setCallbackImpl(cookie, &Callbacks::out, cb);
1328}
1329
1330sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1331 void* cookie) {
1332 return getCallbackImpl(cookie, &Callbacks::event);
1333}
1334
1335void DeviceHalAidl::setStreamOutEventCallback(
1336 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1337 setCallbackImpl(cookie, &Callbacks::event, cb);
1338}
1339
1340sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1341 void* cookie) {
1342 return getCallbackImpl(cookie, &Callbacks::latency);
1343}
1344
1345void DeviceHalAidl::setStreamOutLatencyModeCallback(
1346 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1347 setCallbackImpl(cookie, &Callbacks::latency, cb);
1348}
1349
1350template<class C>
1351sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1352 std::lock_guard l(mLock);
1353 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1354 return ((it->second).*field).promote();
1355 }
1356 return nullptr;
1357}
1358template<class C>
1359void DeviceHalAidl::setCallbackImpl(
1360 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1361 std::lock_guard l(mLock);
1362 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1363 (it->second).*field = cb;
1364 }
1365}
1366
Mikhail Naganov31d46652023-01-10 18:29:25 +00001367} // namespace android