blob: 0ae1a1f89b29b7bc842e6e784dcb3917a8ba2f95 [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
98} // namespace
99
Mikhail Naganov31d46652023-01-10 18:29:25 +0000100status_t DeviceHalAidl::getSupportedDevices(uint32_t*) {
101 // Obsolete.
102 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +0000103}
104
105status_t DeviceHalAidl::initCheck() {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800106 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000107 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800108 std::vector<AudioPort> ports;
109 RETURN_STATUS_IF_ERROR(
110 statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
111 ALOGW_IF(ports.empty(), "%s: module %s returned an empty list of audio ports",
112 __func__, mInstance.c_str());
113 std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()),
114 [](const auto& p) { return std::make_pair(p.id, p); });
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800115 mDefaultInputPortId = mDefaultOutputPortId = -1;
116 const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
117 for (const auto& pair : mPorts) {
118 const auto& p = pair.second;
119 if (p.ext.getTag() == AudioPortExt::Tag::device &&
120 (p.ext.get<AudioPortExt::Tag::device>().flags & defaultDeviceFlag) != 0) {
121 if (p.flags.getTag() == AudioIoFlags::Tag::input) {
122 mDefaultInputPortId = p.id;
123 } else if (p.flags.getTag() == AudioIoFlags::Tag::output) {
124 mDefaultOutputPortId = p.id;
125 }
126 }
127 }
128 ALOGI("%s: module %s default port ids: input %d, output %d",
129 __func__, mInstance.c_str(), mDefaultInputPortId, mDefaultOutputPortId);
Mikhail Naganov289468a2023-03-29 10:06:15 -0700130 RETURN_STATUS_IF_ERROR(updateRoutes());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800131 std::vector<AudioPortConfig> portConfigs;
132 RETURN_STATUS_IF_ERROR(
133 statusTFromBinderStatus(mModule->getAudioPortConfigs(&portConfigs))); // OK if empty
134 std::transform(portConfigs.begin(), portConfigs.end(),
135 std::inserter(mPortConfigs, mPortConfigs.end()),
136 [](const auto& p) { return std::make_pair(p.id, p); });
137 std::vector<AudioPatch> patches;
138 RETURN_STATUS_IF_ERROR(
139 statusTFromBinderStatus(mModule->getAudioPatches(&patches))); // OK if empty
140 std::transform(patches.begin(), patches.end(),
141 std::inserter(mPatches, mPatches.end()),
142 [](const auto& p) { return std::make_pair(p.id, p); });
Shunkai Yao51202502022-12-12 06:11:46 +0000143 return OK;
144}
145
146status_t DeviceHalAidl::setVoiceVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000147 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000148 if (!mModule) return NO_INIT;
149 std::shared_ptr<ITelephony> telephony;
150 if (ndk::ScopedAStatus status = mModule->getTelephony(&telephony);
151 status.isOk() && telephony != nullptr) {
152 ITelephony::TelecomConfig inConfig{ .voiceVolume = Float{volume} }, outConfig;
153 RETURN_STATUS_IF_ERROR(
154 statusTFromBinderStatus(telephony->setTelecomConfig(inConfig, &outConfig)));
155 ALOGW_IF(outConfig.voiceVolume.has_value() && volume != outConfig.voiceVolume.value().value,
156 "%s: the resulting voice volume %f is not the same as requested %f",
157 __func__, outConfig.voiceVolume.value().value, volume);
158 }
159 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +0000160}
161
162status_t DeviceHalAidl::setMasterVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000163 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000164 if (!mModule) return NO_INIT;
165 return statusTFromBinderStatus(mModule->setMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000166}
167
168status_t DeviceHalAidl::getMasterVolume(float *volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000169 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000170 if (!mModule) return NO_INIT;
171 return statusTFromBinderStatus(mModule->getMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000172}
173
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000174status_t DeviceHalAidl::setMode(audio_mode_t mode) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000175 TIME_CHECK();
176 if (!mModule) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000177 AudioMode audioMode = VALUE_OR_FATAL(::aidl::android::legacy2aidl_audio_mode_t_AudioMode(mode));
178 std::shared_ptr<ITelephony> telephony;
179 if (ndk::ScopedAStatus status = mModule->getTelephony(&telephony);
180 status.isOk() && telephony != nullptr) {
181 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(telephony->switchAudioMode(audioMode)));
182 }
183 return statusTFromBinderStatus(mModule->updateAudioMode(audioMode));
Shunkai Yao51202502022-12-12 06:11:46 +0000184}
185
186status_t DeviceHalAidl::setMicMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000187 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000188 if (!mModule) return NO_INIT;
189 return statusTFromBinderStatus(mModule->setMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000190}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000191
Shunkai Yao51202502022-12-12 06:11:46 +0000192status_t DeviceHalAidl::getMicMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000193 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000194 if (!mModule) return NO_INIT;
195 return statusTFromBinderStatus(mModule->getMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000196}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000197
Shunkai Yao51202502022-12-12 06:11:46 +0000198status_t DeviceHalAidl::setMasterMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000199 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000200 if (!mModule) return NO_INIT;
201 return statusTFromBinderStatus(mModule->setMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000202}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000203
Shunkai Yao51202502022-12-12 06:11:46 +0000204status_t DeviceHalAidl::getMasterMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000205 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000206 if (!mModule) return NO_INIT;
207 return statusTFromBinderStatus(mModule->getMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000208}
209
Mikhail Naganov31d46652023-01-10 18:29:25 +0000210status_t DeviceHalAidl::setParameters(const String8& kvPairs __unused) {
211 TIME_CHECK();
212 if (!mModule) return NO_INIT;
213 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000214 return OK;
215}
216
Mikhail Naganov31d46652023-01-10 18:29:25 +0000217status_t DeviceHalAidl::getParameters(const String8& keys __unused, String8 *values) {
218 TIME_CHECK();
219 values->clear();
220 if (!mModule) return NO_INIT;
221 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000222 return OK;
223}
224
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800225namespace {
226
227class Cleanup {
228 public:
229 typedef void (DeviceHalAidl::*Cleaner)(int32_t);
230
231 Cleanup(DeviceHalAidl* device, Cleaner cleaner, int32_t id) :
232 mDevice(device), mCleaner(cleaner), mId(id) {}
233 ~Cleanup() { clean(); }
234 void clean() {
235 if (mDevice != nullptr) (mDevice->*mCleaner)(mId);
236 disarm();
237 }
238 void disarm() { mDevice = nullptr; }
239
240 private:
241 DeviceHalAidl* mDevice;
242 const Cleaner mCleaner;
243 const int32_t mId;
244};
245
246} // namespace
247
248// Since the order of container elements destruction is unspecified,
249// ensure that cleanups are performed from the most recent one and upwards.
250// This is the same as if there were individual Cleanup instances on the stack,
251// however the bonus is that we can disarm all of them with just one statement.
252class DeviceHalAidl::Cleanups : public std::forward_list<Cleanup> {
253 public:
254 ~Cleanups() { for (auto& c : *this) c.clean(); }
255 void disarmAll() { for (auto& c : *this) c.disarm(); }
256};
257
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800258status_t DeviceHalAidl::getInputBufferSize(const struct audio_config* config, size_t* size) {
259 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
260 if (size == nullptr) return BAD_VALUE;
261 TIME_CHECK();
262 if (!mModule) return NO_INIT;
263 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
264 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
265 AudioDevice aidlDevice;
266 aidlDevice.type.type = AudioDeviceType::IN_DEFAULT;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800267 AudioSource aidlSource = AudioSource::DEFAULT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800268 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
269 AudioPortConfig mixPortConfig;
270 Cleanups cleanups;
271 audio_config writableConfig = *config;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700272 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800273 RETURN_STATUS_IF_ERROR(prepareToOpenStream(0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700274 &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800275 *size = aidlConfig.frameCount *
276 getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
277 // Do not disarm cleanups to release temporary port configs.
278 return OK;
279}
280
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800281status_t DeviceHalAidl::prepareToOpenStream(
282 int32_t aidlHandle, const AudioDevice& aidlDevice, const AudioIoFlags& aidlFlags,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800283 AudioSource aidlSource, struct audio_config* config,
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800284 Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700285 AudioPatch* aidlPatch) {
286 ALOGD("%p %s::%s: handle %d, device %s, flags %s, source %s, config %s, mix port config %s",
287 this, getClassName().c_str(), __func__, aidlHandle, aidlDevice.toString().c_str(),
288 aidlFlags.toString().c_str(), toString(aidlSource).c_str(),
289 aidlConfig->toString().c_str(), mixPortConfig->toString().c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800290 const bool isInput = aidlFlags.getTag() == AudioIoFlags::Tag::input;
291 // Find / create AudioPortConfigs for the device port and the mix port,
292 // then find / create a patch between them, and open a stream on the mix port.
293 AudioPortConfig devicePortConfig;
294 bool created = false;
295 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, &devicePortConfig, &created));
296 if (created) {
297 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
298 }
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800299 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*aidlConfig, aidlFlags, aidlHandle, aidlSource,
Mikhail Naganov289468a2023-03-29 10:06:15 -0700300 std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800301 if (created) {
302 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
303 }
304 setConfigFromPortConfig(aidlConfig, *mixPortConfig);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800305 if (isInput) {
306 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700307 {devicePortConfig.id}, {mixPortConfig->id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800308 } else {
309 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
Mikhail Naganove93a0862023-03-15 17:06:59 -0700310 {mixPortConfig->id}, {devicePortConfig.id}, aidlPatch, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800311 }
312 if (created) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700313 cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, aidlPatch->id);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800314 }
315 if (aidlConfig->frameCount <= 0) {
Mikhail Naganove93a0862023-03-15 17:06:59 -0700316 aidlConfig->frameCount = aidlPatch->minimumStreamBufferSizeFrames;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800317 }
318 *config = VALUE_OR_RETURN_STATUS(
319 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(*aidlConfig, isInput));
320 return OK;
321}
322
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800323namespace {
324
325class StreamCallbackBase {
326 protected:
327 explicit StreamCallbackBase(const sp<CallbackBroker>& broker) : mBroker(broker) {}
328 public:
329 void* getCookie() const { return mCookie; }
330 void setCookie(void* cookie) { mCookie = cookie; }
331 sp<CallbackBroker> getBroker() const {
332 if (void* cookie = mCookie; cookie != nullptr) return mBroker.promote();
333 return nullptr;
334 }
335 private:
336 const wp<CallbackBroker> mBroker;
337 std::atomic<void*> mCookie;
338};
339
340template<class C>
341class StreamCallbackBaseHelper {
342 protected:
343 explicit StreamCallbackBaseHelper(const StreamCallbackBase& base) : mBase(base) {}
344 sp<C> getCb(const sp<CallbackBroker>& broker, void* cookie);
345 using CbRef = const sp<C>&;
346 ndk::ScopedAStatus runCb(const std::function<void(CbRef cb)>& f) {
347 if (auto cb = getCb(mBase.getBroker(), mBase.getCookie()); cb != nullptr) f(cb);
348 return ndk::ScopedAStatus::ok();
349 }
350 private:
351 const StreamCallbackBase& mBase;
352};
353
354template<>
355sp<StreamOutHalInterfaceCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>::getCb(
356 const sp<CallbackBroker>& broker, void* cookie) {
357 if (broker != nullptr) return broker->getStreamOutCallback(cookie);
358 return nullptr;
359}
360
361template<>
362sp<StreamOutHalInterfaceEventCallback>
363StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::getCb(
364 const sp<CallbackBroker>& broker, void* cookie) {
365 if (broker != nullptr) return broker->getStreamOutEventCallback(cookie);
366 return nullptr;
367}
368
369template<>
370sp<StreamOutHalInterfaceLatencyModeCallback>
371StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::getCb(
372 const sp<CallbackBroker>& broker, void* cookie) {
373 if (broker != nullptr) return broker->getStreamOutLatencyModeCallback(cookie);
374 return nullptr;
375}
376
377/*
378Note on the callback ownership.
379
380In the Binder ownership model, the server implementation is kept alive
381as long as there is any client (proxy object) alive. This is done by
382incrementing the refcount of the server-side object by the Binder framework.
383When it detects that the last client is gone, it decrements the refcount back.
384
385Thus, it is not needed to keep any references to StreamCallback on our
386side (after we have sent an instance to the client), because we are
387the server-side. The callback object will be kept alive as long as the HAL server
388holds a strong ref to IStreamCallback proxy.
389*/
390
391class OutputStreamCallbackAidl : public StreamCallbackBase,
392 public StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>,
393 public ::aidl::android::hardware::audio::core::BnStreamCallback {
394 public:
395 explicit OutputStreamCallbackAidl(const sp<CallbackBroker>& broker)
396 : StreamCallbackBase(broker),
397 StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>(
398 *static_cast<StreamCallbackBase*>(this)) {}
399 ndk::ScopedAStatus onTransferReady() override {
400 return runCb([](CbRef cb) { cb->onWriteReady(); });
401 }
402 ndk::ScopedAStatus onError() override {
403 return runCb([](CbRef cb) { cb->onError(); });
404 }
405 ndk::ScopedAStatus onDrainReady() override {
406 return runCb([](CbRef cb) { cb->onDrainReady(); });
407 }
408};
409
410class OutputStreamEventCallbackAidl :
411 public StreamCallbackBase,
412 public StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>,
413 public StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>,
414 public ::aidl::android::hardware::audio::core::BnStreamOutEventCallback {
415 public:
416 explicit OutputStreamEventCallbackAidl(const sp<CallbackBroker>& broker)
417 : StreamCallbackBase(broker),
418 StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>(
419 *static_cast<StreamCallbackBase*>(this)),
420 StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>(
421 *static_cast<StreamCallbackBase*>(this)) {}
422 ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& in_audioMetadata) override {
423 std::basic_string<uint8_t> halMetadata(in_audioMetadata.begin(), in_audioMetadata.end());
424 return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb(
425 [&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); });
426 }
427 ndk::ScopedAStatus onRecommendedLatencyModeChanged(
428 const std::vector<AudioLatencyMode>& in_modes) override {
429 auto halModes = VALUE_OR_FATAL(
430 ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
431 in_modes,
432 ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
433 return StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::runCb(
434 [&halModes](auto cb) { cb->onRecommendedLatencyModeChanged(halModes); });
435 }
436};
437
438} // namespace
439
Mikhail Naganov31d46652023-01-10 18:29:25 +0000440status_t DeviceHalAidl::openOutputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800441 audio_io_handle_t handle, audio_devices_t devices,
442 audio_output_flags_t flags, struct audio_config* config,
443 const char* address,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000444 sp<StreamOutHalInterface>* outStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800445 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000446 if (!outStream || !config) {
447 return BAD_VALUE;
448 }
449 TIME_CHECK();
450 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800451 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
452 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
453 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
454 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, false /*isInput*/));
455 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
456 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
457 int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
458 ::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
459 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
460 AudioPortConfig mixPortConfig;
461 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700462 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800463 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
464 AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700465 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800466 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
467 args.portConfigId = mixPortConfig.id;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800468 const bool isOffload = isBitPositionFlagSet(
469 aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD);
470 std::shared_ptr<OutputStreamCallbackAidl> streamCb;
471 if (isOffload) {
472 streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
473 }
474 auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
475 if (isOffload) {
476 args.offloadInfo = aidlConfig.offloadInfo;
477 args.callback = streamCb;
478 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800479 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800480 args.eventCallback = eventCb;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800481 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
482 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800483 StreamContextAidl context(ret.desc, isOffload);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800484 if (!context.isValid()) {
485 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
486 __func__, ret.desc.toString().c_str());
487 return NO_INIT;
488 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700489 *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800490 std::move(ret.stream), this /*callbackBroker*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700491 mStreams.insert(std::pair(*outStream, aidlPatch.id));
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800492 void* cbCookie = (*outStream).get();
493 {
494 std::lock_guard l(mLock);
495 mCallbacks.emplace(cbCookie, Callbacks{});
496 }
497 if (streamCb) streamCb->setCookie(cbCookie);
498 eventCb->setCookie(cbCookie);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800499 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000500 return OK;
501}
502
Mikhail Naganov31d46652023-01-10 18:29:25 +0000503status_t DeviceHalAidl::openInputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800504 audio_io_handle_t handle, audio_devices_t devices,
505 struct audio_config* config, audio_input_flags_t flags,
506 const char* address, audio_source_t source,
507 audio_devices_t outputDevice, const char* outputDeviceAddress,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000508 sp<StreamInHalInterface>* inStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800509 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000510 if (!inStream || !config) {
511 return BAD_VALUE;
512 }
513 TIME_CHECK();
514 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800515 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
516 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
517 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
518 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
519 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
520 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
521 int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
522 ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
523 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
524 AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
525 ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
526 AudioPortConfig mixPortConfig;
527 Cleanups cleanups;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700528 AudioPatch aidlPatch;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800529 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, aidlSource,
Mikhail Naganove93a0862023-03-15 17:06:59 -0700530 config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800531 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
532 args.portConfigId = mixPortConfig.id;
533 RecordTrackMetadata aidlTrackMetadata{
534 .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
535 if (outputDevice != AUDIO_DEVICE_NONE) {
536 aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
537 ::aidl::android::legacy2aidl_audio_device_AudioDevice(
538 outputDevice, outputDeviceAddress));
539 }
540 args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
541 args.bufferSizeFrames = aidlConfig.frameCount;
542 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
543 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800544 StreamContextAidl context(ret.desc, false /*isAsynchronous*/);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800545 if (!context.isValid()) {
546 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
547 __func__, ret.desc.toString().c_str());
548 return NO_INIT;
549 }
Mikhail Naganove93a0862023-03-15 17:06:59 -0700550 *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800551 std::move(ret.stream), this /*micInfoProvider*/);
Mikhail Naganove93a0862023-03-15 17:06:59 -0700552 mStreams.insert(std::pair(*inStream, aidlPatch.id));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800553 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000554 return OK;
555}
556
557status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
558 *supportsPatches = true;
559 return OK;
560}
561
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800562status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
563 const struct audio_port_config* sources,
564 unsigned int num_sinks,
565 const struct audio_port_config* sinks,
566 audio_patch_handle_t* patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800567 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000568 TIME_CHECK();
569 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800570 if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
571 sources == nullptr || sinks == nullptr || patch == nullptr) {
572 return BAD_VALUE;
573 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800574 // When the patch handle (*patch) is AUDIO_PATCH_HANDLE_NONE, it means
575 // the framework wants to create a new patch. The handle has to be generated
576 // by the HAL. Since handles generated this way can only be unique within
577 // a HAL module, the framework generates a globally unique handle, and maps
578 // it on the <HAL module, patch handle> pair.
579 // When the patch handle is set, it meant the framework intends to update
580 // an existing patch.
581 //
582 // This behavior corresponds to HAL module behavior, with the only difference
583 // that the HAL module uses `int32_t` for patch IDs. The following assert ensures
584 // that both the framework and the HAL use the same value for "no ID":
585 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
586 int32_t halPatchId = static_cast<int32_t>(*patch);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800587
588 // Upon conversion, mix port configs contain audio configuration, while
589 // device port configs contain device address. This data is used to find
590 // or create HAL configs.
591 std::vector<AudioPortConfig> aidlSources, aidlSinks;
592 for (unsigned int i = 0; i < num_sources; ++i) {
593 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
594 sources[i].role, sources[i].type)) ==
595 ::aidl::android::AudioPortDirection::INPUT;
596 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
597 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
598 sources[i], isInput, 0)));
599 }
600 for (unsigned int i = 0; i < num_sinks; ++i) {
601 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
602 sinks[i].role, sinks[i].type)) ==
603 ::aidl::android::AudioPortDirection::INPUT;
604 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
605 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
606 sinks[i], isInput, 0)));
607 }
608 Cleanups cleanups;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800609 auto existingPatchIt = halPatchId != 0 ? mPatches.find(halPatchId): mPatches.end();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800610 AudioPatch aidlPatch;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800611 if (existingPatchIt != mPatches.end()) {
612 aidlPatch = existingPatchIt->second;
613 aidlPatch.sourcePortConfigIds.clear();
614 aidlPatch.sinkPortConfigIds.clear();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800615 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800616 ALOGD("%s: sources: %s, sinks: %s",
617 __func__, ::android::internal::ToString(aidlSources).c_str(),
618 ::android::internal::ToString(aidlSinks).c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800619 auto fillPortConfigs = [&](
Mikhail Naganov289468a2023-03-29 10:06:15 -0700620 const std::vector<AudioPortConfig>& configs,
621 const std::set<int32_t>& destinationPortIds,
622 std::vector<int32_t>* ids, std::set<int32_t>* portIds) -> status_t {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800623 for (const auto& s : configs) {
624 AudioPortConfig portConfig;
625 bool created = false;
Mikhail Naganov289468a2023-03-29 10:06:15 -0700626 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
627 s, destinationPortIds, &portConfig, &created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800628 if (created) {
629 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, portConfig.id);
630 }
631 ids->push_back(portConfig.id);
Mikhail Naganov289468a2023-03-29 10:06:15 -0700632 if (portIds != nullptr) {
633 portIds->insert(portConfig.portId);
634 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800635 }
636 return OK;
637 };
Mikhail Naganov289468a2023-03-29 10:06:15 -0700638 // When looking up port configs, the destinationPortId is only used for mix ports.
639 // Thus, we process device port configs first, and look up the destination port ID from them.
640 bool sourceIsDevice = std::any_of(aidlSources.begin(), aidlSources.end(),
641 [](const auto& config) { return config.ext.getTag() == AudioPortExt::device; });
642 const std::vector<AudioPortConfig>& devicePortConfigs =
643 sourceIsDevice ? aidlSources : aidlSinks;
644 std::vector<int32_t>* devicePortConfigIds =
645 sourceIsDevice ? &aidlPatch.sourcePortConfigIds : &aidlPatch.sinkPortConfigIds;
646 const std::vector<AudioPortConfig>& mixPortConfigs =
647 sourceIsDevice ? aidlSinks : aidlSources;
648 std::vector<int32_t>* mixPortConfigIds =
649 sourceIsDevice ? &aidlPatch.sinkPortConfigIds : &aidlPatch.sourcePortConfigIds;
650 std::set<int32_t> devicePortIds;
651 RETURN_STATUS_IF_ERROR(fillPortConfigs(
652 devicePortConfigs, std::set<int32_t>(), devicePortConfigIds, &devicePortIds));
653 RETURN_STATUS_IF_ERROR(fillPortConfigs(
654 mixPortConfigs, devicePortIds, mixPortConfigIds, nullptr));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800655 if (existingPatchIt != mPatches.end()) {
656 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
657 mModule->setAudioPatch(aidlPatch, &aidlPatch)));
658 existingPatchIt->second = aidlPatch;
659 } else {
660 bool created = false;
661 RETURN_STATUS_IF_ERROR(findOrCreatePatch(aidlPatch, &aidlPatch, &created));
662 // Since no cleanup of the patch is needed, 'created' is ignored.
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800663 halPatchId = aidlPatch.id;
664 *patch = static_cast<audio_patch_handle_t>(halPatchId);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800665 }
666 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000667 return OK;
668}
669
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800670status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800671 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000672 TIME_CHECK();
673 if (!mModule) return NO_INIT;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800674 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
675 if (patch == AUDIO_PATCH_HANDLE_NONE) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800676 return BAD_VALUE;
677 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800678 int32_t halPatchId = static_cast<int32_t>(patch);
679 auto patchIt = mPatches.find(halPatchId);
680 if (patchIt == mPatches.end()) {
681 ALOGE("%s: patch with id %d not found", __func__, halPatchId);
682 return BAD_VALUE;
683 }
684 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->resetAudioPatch(halPatchId)));
685 mPatches.erase(patchIt);
Shunkai Yao51202502022-12-12 06:11:46 +0000686 return OK;
687}
688
Mikhail Naganove93a0862023-03-15 17:06:59 -0700689status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
690 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000691 TIME_CHECK();
692 if (!mModule) return NO_INIT;
Mikhail Naganove93a0862023-03-15 17:06:59 -0700693 if (port == nullptr) {
694 return BAD_VALUE;
695 }
696 audio_port_v7 portV7;
697 audio_populate_audio_port_v7(port, &portV7);
698 RETURN_STATUS_IF_ERROR(getAudioPort(&portV7));
699 return audio_populate_audio_port(&portV7, port) ? OK : BAD_VALUE;
700}
701
702status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
703 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
704 TIME_CHECK();
705 if (!mModule) return NO_INIT;
706 if (port == nullptr) {
707 return BAD_VALUE;
708 }
709 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
710 ::aidl::android::AudioPortDirection::INPUT;
711 auto aidlPort = VALUE_OR_RETURN_STATUS(
712 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
713 if (aidlPort.ext.getTag() != AudioPortExt::device) {
714 ALOGE("%s: provided port is not a device port (module %s): %s",
715 __func__, mInstance.c_str(), aidlPort.toString().c_str());
716 return BAD_VALUE;
717 }
718 const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
719 // It seems that we don't have to call HAL since all valid ports have been added either
720 // during initialization, or while handling connection of an external device.
721 auto portsIt = findPort(matchDevice);
722 if (portsIt == mPorts.end()) {
723 ALOGE("%s: device port for device %s is not found in the module %s",
724 __func__, matchDevice.toString().c_str(), mInstance.c_str());
725 return BAD_VALUE;
726 }
727 const int32_t fwkId = aidlPort.id;
728 aidlPort = portsIt->second;
729 aidlPort.id = fwkId;
730 *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
731 aidlPort, isInput));
732 return OK;
733}
734
735status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
736 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
737 TIME_CHECK();
738 if (!mModule) return NO_INIT;
739 if (config == nullptr) {
740 return BAD_VALUE;
741 }
742 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
743 config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
744 AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
745 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
746 *config, isInput, 0 /*portId*/));
747 AudioPortConfig portConfig;
748 bool created = false;
Mikhail Naganov289468a2023-03-29 10:06:15 -0700749 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
750 requestedPortConfig, std::set<int32_t>(), &portConfig, &created));
Shunkai Yao51202502022-12-12 06:11:46 +0000751 return OK;
752}
753
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800754MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
755 if (mMicrophones.status == Microphones::Status::UNKNOWN) {
756 TIME_CHECK();
757 std::vector<MicrophoneInfo> aidlInfo;
758 status_t status = statusTFromBinderStatus(mModule->getMicrophones(&aidlInfo));
759 if (status == OK) {
760 mMicrophones.status = Microphones::Status::QUERIED;
761 mMicrophones.info = std::move(aidlInfo);
762 } else if (status == INVALID_OPERATION) {
763 mMicrophones.status = Microphones::Status::NOT_SUPPORTED;
764 } else {
765 ALOGE("%s: Unexpected status from 'IModule.getMicrophones': %d", __func__, status);
766 return {};
767 }
768 }
769 if (mMicrophones.status == Microphones::Status::QUERIED) {
770 return &mMicrophones.info;
771 }
772 return {}; // NOT_SUPPORTED
773}
774
Shunkai Yao51202502022-12-12 06:11:46 +0000775status_t DeviceHalAidl::getMicrophones(
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800776 std::vector<audio_microphone_characteristic_t>* microphones) {
777 if (!microphones) {
778 return BAD_VALUE;
779 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000780 TIME_CHECK();
781 if (!mModule) return NO_INIT;
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800782 auto staticInfo = getMicrophoneInfo();
783 if (!staticInfo) return INVALID_OPERATION;
784 std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
785 emptyDynamicInfo.reserve(staticInfo->size());
786 std::transform(staticInfo->begin(), staticInfo->end(), std::back_inserter(emptyDynamicInfo),
787 [](const auto& info) { return MicrophoneDynamicInfo{ .id = info.id }; });
788 *microphones = VALUE_OR_RETURN_STATUS(
789 ::aidl::android::convertContainers<std::vector<audio_microphone_characteristic_t>>(
790 *staticInfo, emptyDynamicInfo,
791 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t)
792 );
Shunkai Yao51202502022-12-12 06:11:46 +0000793 return OK;
794}
795
Mikhail Naganov31d46652023-01-10 18:29:25 +0000796status_t DeviceHalAidl::addDeviceEffect(audio_port_handle_t device __unused,
797 sp<EffectHalInterface> effect) {
Shunkai Yao51202502022-12-12 06:11:46 +0000798 if (!effect) {
799 return BAD_VALUE;
800 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000801 TIME_CHECK();
802 if (!mModule) return NO_INIT;
803 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000804 return OK;
805}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000806status_t DeviceHalAidl::removeDeviceEffect(audio_port_handle_t device __unused,
Shunkai Yao51202502022-12-12 06:11:46 +0000807 sp<EffectHalInterface> effect) {
808 if (!effect) {
809 return BAD_VALUE;
810 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000811 TIME_CHECK();
812 if (!mModule) return NO_INIT;
813 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000814 return OK;
815}
816
817status_t DeviceHalAidl::getMmapPolicyInfos(
David Li9cf5e622023-03-21 00:51:10 +0800818 media::audio::common::AudioMMapPolicyType policyType,
819 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000820 TIME_CHECK();
Mikhail Naganov25bc9a22023-04-21 18:48:16 -0700821 AudioMMapPolicyType mmapPolicyType = VALUE_OR_RETURN_STATUS(
822 cpp2ndk_AudioMMapPolicyType(policyType));
David Li9cf5e622023-03-21 00:51:10 +0800823
824 std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
825
826 if (status_t status = statusTFromBinderStatus(
827 mModule->getMmapPolicyInfos(mmapPolicyType, &mmapPolicyInfos)); status != OK) {
828 return status;
829 }
830
831 *policyInfos = VALUE_OR_RETURN_STATUS(
832 convertContainer<std::vector<media::audio::common::AudioMMapPolicyInfo>>(
833 mmapPolicyInfos, ndk2cpp_AudioMMapPolicyInfo));
Shunkai Yao51202502022-12-12 06:11:46 +0000834 return OK;
835}
836
837int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000838 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800839 int32_t mixerBurstCount = 0;
840 if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
841 return mixerBurstCount;
842 }
843 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000844}
845
846int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000847 TIME_CHECK();
David Li9cf5e622023-03-21 00:51:10 +0800848 int32_t hardwareBurstMinUsec = 0;
849 if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
850 return hardwareBurstMinUsec;
851 }
852 return 0;
Shunkai Yao51202502022-12-12 06:11:46 +0000853}
854
855error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000856 TIME_CHECK();
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700857 if (!mModule) return NO_INIT;
858 int32_t aidlHwAvSync;
859 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
860 return VALUE_OR_RETURN_STATUS(
861 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +0000862}
863
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000864status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
865 TIME_CHECK();
866 if (!mModule) return NO_INIT;
867 return mModule->dump(fd, Args(args).args(), args.size());
David Li9cf5e622023-03-21 00:51:10 +0800868}
Shunkai Yao51202502022-12-12 06:11:46 +0000869
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700870int32_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000871 TIME_CHECK();
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700872 if (!mModule) return NO_INIT;
873 if (supports == nullptr) {
874 return BAD_VALUE;
875 }
876 return statusTFromBinderStatus(mModule->supportsVariableLatency(supports));
Shunkai Yao51202502022-12-12 06:11:46 +0000877}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000878
Mikhail Naganove93a0862023-03-15 17:06:59 -0700879status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
880 TIME_CHECK();
881 if (!mModule) return NO_INIT;
882 if (port == nullptr) {
883 return BAD_VALUE;
884 }
885 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
886 ::aidl::android::AudioPortDirection::INPUT;
887 AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
888 ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
889 if (aidlPort.ext.getTag() != AudioPortExt::device) {
890 ALOGE("%s: provided port is not a device port (module %s): %s",
891 __func__, mInstance.c_str(), aidlPort.toString().c_str());
892 return BAD_VALUE;
893 }
894 if (connected) {
895 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
896 // Reset the device address to find the "template" port.
897 matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
898 auto portsIt = findPort(matchDevice);
899 if (portsIt == mPorts.end()) {
900 ALOGW("%s: device port for device %s is not found in the module %s",
901 __func__, matchDevice.toString().c_str(), mInstance.c_str());
902 return BAD_VALUE;
903 }
904 // Use the ID of the "template" port, use all the information from the provided port.
905 aidlPort.id = portsIt->first;
906 AudioPort connectedPort;
907 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
908 aidlPort, &connectedPort)));
909 const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
910 LOG_ALWAYS_FATAL_IF(!inserted,
911 "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
912 __func__, mInstance.c_str(), connectedPort.toString().c_str(),
913 it->second.toString().c_str());
914 } else { // !connected
915 AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
916 auto portsIt = findPort(matchDevice);
917 if (portsIt == mPorts.end()) {
918 ALOGW("%s: device port for device %s is not found in the module %s",
919 __func__, matchDevice.toString().c_str(), mInstance.c_str());
920 return BAD_VALUE;
921 }
922 // Any streams opened on the external device must be closed by this time,
923 // thus we can clean up patches and port configs that were created for them.
924 resetUnusedPatchesAndPortConfigs();
925 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
926 portsIt->second.id)));
927 mPorts.erase(portsIt);
928 }
Mikhail Naganov289468a2023-03-29 10:06:15 -0700929 return updateRoutes();
Mikhail Naganove93a0862023-03-15 17:06:59 -0700930}
931
932status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
933 TIME_CHECK();
934 if (!mModule) return NO_INIT;
935 ModuleDebug debug{ .simulateDeviceConnections = enabled };
936 status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
937 // This is important to log as it affects HAL behavior.
938 if (status == OK) {
939 ALOGI("%s: set enabled: %d", __func__, enabled);
940 } else {
941 ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
942 }
943 return status;
944}
945
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800946bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
947 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
948 return p.ext.get<AudioPortExt::Tag::device>().device == device;
949}
950
951bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
952 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
953 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
954 return p.portId == mDefaultInputPortId;
955 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
956 return p.portId == mDefaultOutputPortId;
957 }
958 return p.ext.get<AudioPortExt::Tag::device>().device == device;
959}
960
David Lia8675d42023-03-30 21:08:06 +0800961status_t DeviceHalAidl::createOrUpdatePortConfig(
962 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool* created) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800963 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800964 AudioPortConfig appliedPortConfig;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800965 bool applied = false;
966 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800967 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800968 if (!applied) {
969 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800970 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800971 if (!applied) {
972 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800973 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800974 return NO_INIT;
975 }
976 }
David Lia8675d42023-03-30 21:08:06 +0800977
978 int32_t id = appliedPortConfig.id;
979 if (requestedPortConfig.id != 0 && requestedPortConfig.id != id) {
980 LOG_ALWAYS_FATAL("%s: requested port config id %d changed to %d", __func__,
981 requestedPortConfig.id, id);
982 }
983
984 auto [it, inserted] = mPortConfigs.insert_or_assign(std::move(id),
985 std::move(appliedPortConfig));
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800986 *result = it;
David Lia8675d42023-03-30 21:08:06 +0800987 *created = inserted;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800988 return OK;
989}
990
991status_t DeviceHalAidl::findOrCreatePatch(
992 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
993 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
994 requestedPatch.sourcePortConfigIds.end());
995 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
996 requestedPatch.sinkPortConfigIds.end());
997 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
998}
999
1000status_t DeviceHalAidl::findOrCreatePatch(
1001 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
1002 AudioPatch* patch, bool* created) {
1003 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
1004 if (patchIt == mPatches.end()) {
1005 TIME_CHECK();
1006 AudioPatch requestedPatch, appliedPatch;
1007 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
1008 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
1009 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
1010 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
1011 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
1012 requestedPatch, &appliedPatch)));
1013 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
1014 *created = true;
1015 } else {
1016 *created = false;
1017 }
1018 *patch = patchIt->second;
1019 return OK;
1020}
1021
1022status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device,
1023 AudioPortConfig* portConfig, bool* created) {
1024 auto portConfigIt = findPortConfig(device);
1025 if (portConfigIt == mPortConfigs.end()) {
1026 auto portsIt = findPort(device);
1027 if (portsIt == mPorts.end()) {
1028 ALOGE("%s: device port for device %s is not found in the module %s",
1029 __func__, device.toString().c_str(), mInstance.c_str());
1030 return BAD_VALUE;
1031 }
1032 AudioPortConfig requestedPortConfig;
1033 requestedPortConfig.portId = portsIt->first;
David Lia8675d42023-03-30 21:08:06 +08001034 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1035 created));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001036 } else {
1037 *created = false;
1038 }
1039 *portConfig = portConfigIt->second;
1040 return OK;
1041}
1042
1043status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001044 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001045 AudioSource source, const std::set<int32_t>& destinationPortIds,
1046 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001047 // These flags get removed one by one in this order when retrying port finding.
1048 static const std::vector<AudioInputFlags> kOptionalInputFlags{
1049 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001050 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001051 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001052 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
1053 AudioIoFlags matchFlags = flags.value();
Mikhail Naganov289468a2023-03-29 10:06:15 -07001054 auto portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001055 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
1056 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
1057 if (!isBitPositionFlagSet(
1058 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
1059 ++optionalInputFlagsIt;
1060 continue;
1061 }
1062 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
1063 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
Mikhail Naganov289468a2023-03-29 10:06:15 -07001064 portsIt = findPort(config, matchFlags, destinationPortIds);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001065 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
1066 "retried with flags %s", __func__, config.toString().c_str(),
1067 flags.value().toString().c_str(), mInstance.c_str(),
1068 matchFlags.toString().c_str());
1069 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001070 if (portsIt == mPorts.end()) {
1071 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001072 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001073 mInstance.c_str());
1074 return BAD_VALUE;
1075 }
1076 AudioPortConfig requestedPortConfig;
1077 requestedPortConfig.portId = portsIt->first;
1078 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001079 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001080 if (matchFlags.getTag() == AudioIoFlags::Tag::input
1081 && source != AudioSource::SYS_RESERVED_INVALID) {
1082 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
1083 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
1084 }
David Lia8675d42023-03-30 21:08:06 +08001085 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1086 created));
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001087 } else if (!flags.has_value()) {
1088 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
1089 "and was not created as flags are not specified",
1090 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
1091 return BAD_VALUE;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001092 } else {
David Lia8675d42023-03-30 21:08:06 +08001093 AudioPortConfig requestedPortConfig = portConfigIt->second;
1094 if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
1095 AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
1096 if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
1097 source != AudioSource::SYS_RESERVED_INVALID) {
1098 mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
1099 }
1100 }
1101
1102 if (requestedPortConfig != portConfigIt->second) {
1103 RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
1104 created));
1105 } else {
1106 *created = false;
1107 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001108 }
1109 *portConfig = portConfigIt->second;
1110 return OK;
1111}
1112
1113status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001114 const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
1115 AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001116 using Tag = AudioPortExt::Tag;
1117 if (requestedPortConfig.ext.getTag() == Tag::mix) {
1118 if (const auto& p = requestedPortConfig;
1119 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001120 !p.format.has_value()) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001121 ALOGW("%s: provided mix port config is not fully specified: %s",
1122 __func__, p.toString().c_str());
1123 return BAD_VALUE;
1124 }
1125 AudioConfig config;
1126 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -08001127 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
1128 AudioPortMixExtUseCase::Tag::source ?
1129 requestedPortConfig.ext.get<Tag::mix>().usecase.
1130 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001131 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganov289468a2023-03-29 10:06:15 -07001132 requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
1133 portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001134 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
1135 return findOrCreatePortConfig(
1136 requestedPortConfig.ext.get<Tag::device>().device, portConfig, created);
1137 }
1138 ALOGW("%s: unsupported audio port config: %s",
1139 __func__, requestedPortConfig.toString().c_str());
1140 return BAD_VALUE;
1141}
1142
1143DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
1144 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
1145 return std::find_if(mPatches.begin(), mPatches.end(),
1146 [&](const auto& pair) {
1147 const auto& p = pair.second;
1148 std::set<int32_t> patchSrcs(
1149 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
1150 std::set<int32_t> patchSinks(
1151 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
1152 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
1153}
1154
1155DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001156 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
1157 return mPorts.find(mDefaultInputPortId);
1158 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
1159 return mPorts.find(mDefaultOutputPortId);
1160 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001161 return std::find_if(mPorts.begin(), mPorts.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001162 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001163}
1164
Mikhail Naganov289468a2023-03-29 10:06:15 -07001165
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001166DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
Mikhail Naganov289468a2023-03-29 10:06:15 -07001167 const AudioConfig& config, const AudioIoFlags& flags,
1168 const std::set<int32_t>& destinationPortIds) {
Mikhail Naganove93a0862023-03-15 17:06:59 -07001169 auto belongsToProfile = [&config](const AudioProfile& prof) {
1170 return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
1171 (config.base.channelMask.getTag() == AudioChannelLayout::none ||
1172 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
1173 config.base.channelMask) != prof.channelMasks.end()) &&
1174 (config.base.sampleRate == 0 ||
1175 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
1176 config.base.sampleRate) != prof.sampleRates.end());
1177 };
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001178 auto matcher = [&](const auto& pair) {
1179 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001180 return p.ext.getTag() == AudioPortExt::Tag::mix &&
1181 p.flags == flags &&
Mikhail Naganov289468a2023-03-29 10:06:15 -07001182 (destinationPortIds.empty() ||
1183 std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
1184 [&](const int32_t destId) { return mRoutingMatrix.count(
1185 std::make_pair(p.id, destId)) != 0; })) &&
Mikhail Naganove93a0862023-03-15 17:06:59 -07001186 (p.profiles.empty() ||
1187 std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
1188 p.profiles.end()); };
Mikhail Naganov1a44bc62023-02-16 17:35:06 -08001189 return std::find_if(mPorts.begin(), mPorts.end(), matcher);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001190}
1191
1192DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001193 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001194 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001195}
1196
1197DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001198 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001199 using Tag = AudioPortExt::Tag;
1200 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
1201 [&](const auto& pair) {
1202 const auto& p = pair.second;
1203 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
1204 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
1205 !p.format.has_value() || !p.flags.has_value(),
1206 "%s: stored mix port config is not fully specified: %s",
1207 __func__, p.toString().c_str());
1208 return p.ext.getTag() == Tag::mix &&
1209 isConfigEqualToPortConfig(config, p) &&
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001210 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001211 p.ext.template get<Tag::mix>().handle == ioHandle; });
1212}
Mikhail Naganove93a0862023-03-15 17:06:59 -07001213
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001214void DeviceHalAidl::resetPatch(int32_t patchId) {
1215 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1216 mPatches.erase(it);
1217 TIME_CHECK();
1218 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1219 ALOGE("%s: error while resetting patch %d: %s",
1220 __func__, patchId, status.getDescription().c_str());
1221 }
1222 return;
1223 }
1224 ALOGE("%s: patch id %d not found", __func__, patchId);
1225}
1226
1227void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1228 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1229 mPortConfigs.erase(it);
1230 TIME_CHECK();
1231 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1232 !status.isOk()) {
1233 ALOGE("%s: error while resetting port config %d: %s",
1234 __func__, portConfigId, status.getDescription().c_str());
1235 }
1236 return;
1237 }
1238 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1239}
1240
Mikhail Naganove93a0862023-03-15 17:06:59 -07001241void DeviceHalAidl::resetUnusedPatches() {
1242 // Since patches can be created independently of streams via 'createAudioPatch',
1243 // here we only clean up patches for released streams.
1244 for (auto it = mStreams.begin(); it != mStreams.end(); ) {
1245 if (auto streamSp = it->first.promote(); streamSp) {
1246 ++it;
1247 } else {
1248 resetPatch(it->second);
1249 it = mStreams.erase(it);
1250 }
1251 }
1252}
1253
1254void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
1255 resetUnusedPatches();
1256 resetUnusedPortConfigs();
1257}
1258
1259void DeviceHalAidl::resetUnusedPortConfigs() {
1260 // The assumption is that port configs are used to create patches
1261 // (or to open streams, but that involves creation of patches, too). Thus,
1262 // orphaned port configs can and should be reset.
1263 std::set<int32_t> portConfigIds;
1264 std::transform(mPortConfigs.begin(), mPortConfigs.end(),
1265 std::inserter(portConfigIds, portConfigIds.end()),
1266 [](const auto& pcPair) { return pcPair.first; });
1267 for (const auto& p : mPatches) {
1268 for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
1269 for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
1270 }
1271 for (int32_t id : portConfigIds) resetPortConfig(id);
1272}
1273
Mikhail Naganov289468a2023-03-29 10:06:15 -07001274status_t DeviceHalAidl::updateRoutes() {
1275 TIME_CHECK();
1276 std::vector<AudioRoute> routes;
1277 RETURN_STATUS_IF_ERROR(
1278 statusTFromBinderStatus(mModule->getAudioRoutes(&routes)));
1279 ALOGW_IF(routes.empty(), "%s: module %s returned an empty list of audio routes",
1280 __func__, mInstance.c_str());
1281 mRoutingMatrix.clear();
1282 for (const auto& r : routes) {
1283 for (auto portId : r.sourcePortIds) {
1284 mRoutingMatrix.emplace(r.sinkPortId, portId);
1285 mRoutingMatrix.emplace(portId, r.sinkPortId);
1286 }
1287 }
1288 return OK;
1289}
1290
Mikhail Naganovdfd594e2023-02-08 16:59:41 -08001291void DeviceHalAidl::clearCallbacks(void* cookie) {
1292 std::lock_guard l(mLock);
1293 mCallbacks.erase(cookie);
1294}
1295
1296sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1297 return getCallbackImpl(cookie, &Callbacks::out);
1298}
1299
1300void DeviceHalAidl::setStreamOutCallback(
1301 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1302 setCallbackImpl(cookie, &Callbacks::out, cb);
1303}
1304
1305sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1306 void* cookie) {
1307 return getCallbackImpl(cookie, &Callbacks::event);
1308}
1309
1310void DeviceHalAidl::setStreamOutEventCallback(
1311 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1312 setCallbackImpl(cookie, &Callbacks::event, cb);
1313}
1314
1315sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1316 void* cookie) {
1317 return getCallbackImpl(cookie, &Callbacks::latency);
1318}
1319
1320void DeviceHalAidl::setStreamOutLatencyModeCallback(
1321 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1322 setCallbackImpl(cookie, &Callbacks::latency, cb);
1323}
1324
1325template<class C>
1326sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1327 std::lock_guard l(mLock);
1328 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1329 return ((it->second).*field).promote();
1330 }
1331 return nullptr;
1332}
1333template<class C>
1334void DeviceHalAidl::setCallbackImpl(
1335 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1336 std::lock_guard l(mLock);
1337 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1338 (it->second).*field = cb;
1339 }
1340}
1341
Mikhail Naganov31d46652023-01-10 18:29:25 +00001342} // namespace android