blob: cf4d670713cc654f374a15ae1abf96647f377bb7 [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>
28#include <media/AidlConversionUtil.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000029#include <mediautils/TimeCheck.h>
Mikhail Naganov89a9f742023-01-30 12:33:18 -080030#include <Utils.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000031#include <utils/Log.h>
Shunkai Yao51202502022-12-12 06:11:46 +000032
Mikhail Naganov31d46652023-01-10 18:29:25 +000033#include "DeviceHalAidl.h"
34#include "StreamHalAidl.h"
35
Mikhail Naganovfab697c2023-01-11 19:33:13 +000036using aidl::android::aidl_utils::statusTFromBinderStatus;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080037using aidl::android::media::audio::common::AudioConfig;
38using aidl::android::media::audio::common::AudioDevice;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080039using aidl::android::media::audio::common::AudioDeviceType;
40using aidl::android::media::audio::common::AudioInputFlags;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080041using aidl::android::media::audio::common::AudioIoFlags;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -080042using aidl::android::media::audio::common::AudioLatencyMode;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000043using aidl::android::media::audio::common::AudioMode;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080044using aidl::android::media::audio::common::AudioOutputFlags;
45using aidl::android::media::audio::common::AudioPort;
46using aidl::android::media::audio::common::AudioPortConfig;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080047using aidl::android::media::audio::common::AudioPortDeviceExt;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -080048using aidl::android::media::audio::common::AudioPortMixExt;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -080049using aidl::android::media::audio::common::AudioPortMixExtUseCase;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080050using aidl::android::media::audio::common::AudioPortExt;
51using aidl::android::media::audio::common::AudioSource;
52using aidl::android::media::audio::common::Int;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000053using aidl::android::media::audio::common::Float;
Mikhail Naganov6352e822023-03-09 18:22:36 -080054using aidl::android::hardware::audio::common::getFrameSizeInBytes;
55using aidl::android::hardware::audio::common::isBitPositionFlagSet;
56using aidl::android::hardware::audio::common::makeBitPositionFlagMask;
Mikhail Naganovcad0afe2023-03-10 14:25:57 -080057using aidl::android::media::audio::common::MicrophoneDynamicInfo;
58using aidl::android::media::audio::common::MicrophoneInfo;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080059using aidl::android::hardware::audio::common::RecordTrackMetadata;
60using aidl::android::hardware::audio::core::AudioPatch;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000061using aidl::android::hardware::audio::core::IModule;
62using aidl::android::hardware::audio::core::ITelephony;
63using aidl::android::hardware::audio::core::StreamDescriptor;
Mikhail Naganov31d46652023-01-10 18:29:25 +000064
65namespace android {
66
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080067namespace {
68
69bool isConfigEqualToPortConfig(const AudioConfig& config, const AudioPortConfig& portConfig) {
70 return portConfig.sampleRate.value().value == config.base.sampleRate &&
71 portConfig.channelMask.value() == config.base.channelMask &&
72 portConfig.format.value() == config.base.format;
73}
74
75void setConfigFromPortConfig(AudioConfig* config, const AudioPortConfig& portConfig) {
76 config->base.sampleRate = portConfig.sampleRate.value().value;
77 config->base.channelMask = portConfig.channelMask.value();
78 config->base.format = portConfig.format.value();
79}
80
81void setPortConfigFromConfig(AudioPortConfig* portConfig, const AudioConfig& config) {
82 portConfig->sampleRate = Int{ .value = config.base.sampleRate };
83 portConfig->channelMask = config.base.channelMask;
84 portConfig->format = config.base.format;
85}
86
87} // namespace
88
Mikhail Naganov31d46652023-01-10 18:29:25 +000089status_t DeviceHalAidl::getSupportedDevices(uint32_t*) {
90 // Obsolete.
91 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +000092}
93
94status_t DeviceHalAidl::initCheck() {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080095 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +000096 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080097 std::vector<AudioPort> ports;
98 RETURN_STATUS_IF_ERROR(
99 statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
100 ALOGW_IF(ports.empty(), "%s: module %s returned an empty list of audio ports",
101 __func__, mInstance.c_str());
102 std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()),
103 [](const auto& p) { return std::make_pair(p.id, p); });
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800104 mDefaultInputPortId = mDefaultOutputPortId = -1;
105 const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
106 for (const auto& pair : mPorts) {
107 const auto& p = pair.second;
108 if (p.ext.getTag() == AudioPortExt::Tag::device &&
109 (p.ext.get<AudioPortExt::Tag::device>().flags & defaultDeviceFlag) != 0) {
110 if (p.flags.getTag() == AudioIoFlags::Tag::input) {
111 mDefaultInputPortId = p.id;
112 } else if (p.flags.getTag() == AudioIoFlags::Tag::output) {
113 mDefaultOutputPortId = p.id;
114 }
115 }
116 }
117 ALOGI("%s: module %s default port ids: input %d, output %d",
118 __func__, mInstance.c_str(), mDefaultInputPortId, mDefaultOutputPortId);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800119 std::vector<AudioPortConfig> portConfigs;
120 RETURN_STATUS_IF_ERROR(
121 statusTFromBinderStatus(mModule->getAudioPortConfigs(&portConfigs))); // OK if empty
122 std::transform(portConfigs.begin(), portConfigs.end(),
123 std::inserter(mPortConfigs, mPortConfigs.end()),
124 [](const auto& p) { return std::make_pair(p.id, p); });
125 std::vector<AudioPatch> patches;
126 RETURN_STATUS_IF_ERROR(
127 statusTFromBinderStatus(mModule->getAudioPatches(&patches))); // OK if empty
128 std::transform(patches.begin(), patches.end(),
129 std::inserter(mPatches, mPatches.end()),
130 [](const auto& p) { return std::make_pair(p.id, p); });
Shunkai Yao51202502022-12-12 06:11:46 +0000131 return OK;
132}
133
134status_t DeviceHalAidl::setVoiceVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000135 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000136 if (!mModule) return NO_INIT;
137 std::shared_ptr<ITelephony> telephony;
138 if (ndk::ScopedAStatus status = mModule->getTelephony(&telephony);
139 status.isOk() && telephony != nullptr) {
140 ITelephony::TelecomConfig inConfig{ .voiceVolume = Float{volume} }, outConfig;
141 RETURN_STATUS_IF_ERROR(
142 statusTFromBinderStatus(telephony->setTelecomConfig(inConfig, &outConfig)));
143 ALOGW_IF(outConfig.voiceVolume.has_value() && volume != outConfig.voiceVolume.value().value,
144 "%s: the resulting voice volume %f is not the same as requested %f",
145 __func__, outConfig.voiceVolume.value().value, volume);
146 }
147 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +0000148}
149
150status_t DeviceHalAidl::setMasterVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000151 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000152 if (!mModule) return NO_INIT;
153 return statusTFromBinderStatus(mModule->setMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000154}
155
156status_t DeviceHalAidl::getMasterVolume(float *volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000157 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000158 if (!mModule) return NO_INIT;
159 return statusTFromBinderStatus(mModule->getMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000160}
161
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000162status_t DeviceHalAidl::setMode(audio_mode_t mode) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000163 TIME_CHECK();
164 if (!mModule) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000165 AudioMode audioMode = VALUE_OR_FATAL(::aidl::android::legacy2aidl_audio_mode_t_AudioMode(mode));
166 std::shared_ptr<ITelephony> telephony;
167 if (ndk::ScopedAStatus status = mModule->getTelephony(&telephony);
168 status.isOk() && telephony != nullptr) {
169 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(telephony->switchAudioMode(audioMode)));
170 }
171 return statusTFromBinderStatus(mModule->updateAudioMode(audioMode));
Shunkai Yao51202502022-12-12 06:11:46 +0000172}
173
174status_t DeviceHalAidl::setMicMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000175 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000176 if (!mModule) return NO_INIT;
177 return statusTFromBinderStatus(mModule->setMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000178}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000179
Shunkai Yao51202502022-12-12 06:11:46 +0000180status_t DeviceHalAidl::getMicMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000181 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000182 if (!mModule) return NO_INIT;
183 return statusTFromBinderStatus(mModule->getMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000184}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000185
Shunkai Yao51202502022-12-12 06:11:46 +0000186status_t DeviceHalAidl::setMasterMute(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->setMasterMute(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::getMasterMute(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->getMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000196}
197
Mikhail Naganov31d46652023-01-10 18:29:25 +0000198status_t DeviceHalAidl::setParameters(const String8& kvPairs __unused) {
199 TIME_CHECK();
200 if (!mModule) return NO_INIT;
201 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000202 return OK;
203}
204
Mikhail Naganov31d46652023-01-10 18:29:25 +0000205status_t DeviceHalAidl::getParameters(const String8& keys __unused, String8 *values) {
206 TIME_CHECK();
207 values->clear();
208 if (!mModule) return NO_INIT;
209 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000210 return OK;
211}
212
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800213namespace {
214
215class Cleanup {
216 public:
217 typedef void (DeviceHalAidl::*Cleaner)(int32_t);
218
219 Cleanup(DeviceHalAidl* device, Cleaner cleaner, int32_t id) :
220 mDevice(device), mCleaner(cleaner), mId(id) {}
221 ~Cleanup() { clean(); }
222 void clean() {
223 if (mDevice != nullptr) (mDevice->*mCleaner)(mId);
224 disarm();
225 }
226 void disarm() { mDevice = nullptr; }
227
228 private:
229 DeviceHalAidl* mDevice;
230 const Cleaner mCleaner;
231 const int32_t mId;
232};
233
234} // namespace
235
236// Since the order of container elements destruction is unspecified,
237// ensure that cleanups are performed from the most recent one and upwards.
238// This is the same as if there were individual Cleanup instances on the stack,
239// however the bonus is that we can disarm all of them with just one statement.
240class DeviceHalAidl::Cleanups : public std::forward_list<Cleanup> {
241 public:
242 ~Cleanups() { for (auto& c : *this) c.clean(); }
243 void disarmAll() { for (auto& c : *this) c.disarm(); }
244};
245
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800246status_t DeviceHalAidl::getInputBufferSize(const struct audio_config* config, size_t* size) {
247 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
248 if (size == nullptr) return BAD_VALUE;
249 TIME_CHECK();
250 if (!mModule) return NO_INIT;
251 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
252 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
253 AudioDevice aidlDevice;
254 aidlDevice.type.type = AudioDeviceType::IN_DEFAULT;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800255 AudioSource aidlSource = AudioSource::DEFAULT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800256 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
257 AudioPortConfig mixPortConfig;
258 Cleanups cleanups;
259 audio_config writableConfig = *config;
260 int32_t nominalLatency;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800261 RETURN_STATUS_IF_ERROR(prepareToOpenStream(0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
262 &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &nominalLatency));
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800263 *size = aidlConfig.frameCount *
264 getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
265 // Do not disarm cleanups to release temporary port configs.
266 return OK;
267}
268
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800269status_t DeviceHalAidl::prepareToOpenStream(
270 int32_t aidlHandle, const AudioDevice& aidlDevice, const AudioIoFlags& aidlFlags,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800271 AudioSource aidlSource, struct audio_config* config,
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800272 Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
273 int32_t* nominalLatency) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800274 const bool isInput = aidlFlags.getTag() == AudioIoFlags::Tag::input;
275 // Find / create AudioPortConfigs for the device port and the mix port,
276 // then find / create a patch between them, and open a stream on the mix port.
277 AudioPortConfig devicePortConfig;
278 bool created = false;
279 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, &devicePortConfig, &created));
280 if (created) {
281 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
282 }
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800283 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*aidlConfig, aidlFlags, aidlHandle, aidlSource,
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800284 mixPortConfig, &created));
285 if (created) {
286 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
287 }
288 setConfigFromPortConfig(aidlConfig, *mixPortConfig);
289 AudioPatch patch;
290 if (isInput) {
291 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
292 {devicePortConfig.id}, {mixPortConfig->id}, &patch, &created));
293 } else {
294 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
295 {mixPortConfig->id}, {devicePortConfig.id}, &patch, &created));
296 }
297 if (created) {
298 cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, patch.id);
299 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800300 *nominalLatency = patch.latenciesMs[0];
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800301 if (aidlConfig->frameCount <= 0) {
302 aidlConfig->frameCount = patch.minimumStreamBufferSizeFrames;
303 }
304 *config = VALUE_OR_RETURN_STATUS(
305 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(*aidlConfig, isInput));
306 return OK;
307}
308
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800309namespace {
310
311class StreamCallbackBase {
312 protected:
313 explicit StreamCallbackBase(const sp<CallbackBroker>& broker) : mBroker(broker) {}
314 public:
315 void* getCookie() const { return mCookie; }
316 void setCookie(void* cookie) { mCookie = cookie; }
317 sp<CallbackBroker> getBroker() const {
318 if (void* cookie = mCookie; cookie != nullptr) return mBroker.promote();
319 return nullptr;
320 }
321 private:
322 const wp<CallbackBroker> mBroker;
323 std::atomic<void*> mCookie;
324};
325
326template<class C>
327class StreamCallbackBaseHelper {
328 protected:
329 explicit StreamCallbackBaseHelper(const StreamCallbackBase& base) : mBase(base) {}
330 sp<C> getCb(const sp<CallbackBroker>& broker, void* cookie);
331 using CbRef = const sp<C>&;
332 ndk::ScopedAStatus runCb(const std::function<void(CbRef cb)>& f) {
333 if (auto cb = getCb(mBase.getBroker(), mBase.getCookie()); cb != nullptr) f(cb);
334 return ndk::ScopedAStatus::ok();
335 }
336 private:
337 const StreamCallbackBase& mBase;
338};
339
340template<>
341sp<StreamOutHalInterfaceCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>::getCb(
342 const sp<CallbackBroker>& broker, void* cookie) {
343 if (broker != nullptr) return broker->getStreamOutCallback(cookie);
344 return nullptr;
345}
346
347template<>
348sp<StreamOutHalInterfaceEventCallback>
349StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::getCb(
350 const sp<CallbackBroker>& broker, void* cookie) {
351 if (broker != nullptr) return broker->getStreamOutEventCallback(cookie);
352 return nullptr;
353}
354
355template<>
356sp<StreamOutHalInterfaceLatencyModeCallback>
357StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::getCb(
358 const sp<CallbackBroker>& broker, void* cookie) {
359 if (broker != nullptr) return broker->getStreamOutLatencyModeCallback(cookie);
360 return nullptr;
361}
362
363/*
364Note on the callback ownership.
365
366In the Binder ownership model, the server implementation is kept alive
367as long as there is any client (proxy object) alive. This is done by
368incrementing the refcount of the server-side object by the Binder framework.
369When it detects that the last client is gone, it decrements the refcount back.
370
371Thus, it is not needed to keep any references to StreamCallback on our
372side (after we have sent an instance to the client), because we are
373the server-side. The callback object will be kept alive as long as the HAL server
374holds a strong ref to IStreamCallback proxy.
375*/
376
377class OutputStreamCallbackAidl : public StreamCallbackBase,
378 public StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>,
379 public ::aidl::android::hardware::audio::core::BnStreamCallback {
380 public:
381 explicit OutputStreamCallbackAidl(const sp<CallbackBroker>& broker)
382 : StreamCallbackBase(broker),
383 StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>(
384 *static_cast<StreamCallbackBase*>(this)) {}
385 ndk::ScopedAStatus onTransferReady() override {
386 return runCb([](CbRef cb) { cb->onWriteReady(); });
387 }
388 ndk::ScopedAStatus onError() override {
389 return runCb([](CbRef cb) { cb->onError(); });
390 }
391 ndk::ScopedAStatus onDrainReady() override {
392 return runCb([](CbRef cb) { cb->onDrainReady(); });
393 }
394};
395
396class OutputStreamEventCallbackAidl :
397 public StreamCallbackBase,
398 public StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>,
399 public StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>,
400 public ::aidl::android::hardware::audio::core::BnStreamOutEventCallback {
401 public:
402 explicit OutputStreamEventCallbackAidl(const sp<CallbackBroker>& broker)
403 : StreamCallbackBase(broker),
404 StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>(
405 *static_cast<StreamCallbackBase*>(this)),
406 StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>(
407 *static_cast<StreamCallbackBase*>(this)) {}
408 ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& in_audioMetadata) override {
409 std::basic_string<uint8_t> halMetadata(in_audioMetadata.begin(), in_audioMetadata.end());
410 return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb(
411 [&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); });
412 }
413 ndk::ScopedAStatus onRecommendedLatencyModeChanged(
414 const std::vector<AudioLatencyMode>& in_modes) override {
415 auto halModes = VALUE_OR_FATAL(
416 ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
417 in_modes,
418 ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
419 return StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::runCb(
420 [&halModes](auto cb) { cb->onRecommendedLatencyModeChanged(halModes); });
421 }
422};
423
424} // namespace
425
Mikhail Naganov31d46652023-01-10 18:29:25 +0000426status_t DeviceHalAidl::openOutputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800427 audio_io_handle_t handle, audio_devices_t devices,
428 audio_output_flags_t flags, struct audio_config* config,
429 const char* address,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000430 sp<StreamOutHalInterface>* outStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800431 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000432 if (!outStream || !config) {
433 return BAD_VALUE;
434 }
435 TIME_CHECK();
436 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800437 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
438 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
439 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
440 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, false /*isInput*/));
441 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
442 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
443 int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
444 ::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
445 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
446 AudioPortConfig mixPortConfig;
447 Cleanups cleanups;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800448 int32_t nominalLatency;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800449 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
450 AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
451 config, &cleanups, &aidlConfig, &mixPortConfig, &nominalLatency));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800452 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
453 args.portConfigId = mixPortConfig.id;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800454 const bool isOffload = isBitPositionFlagSet(
455 aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD);
456 std::shared_ptr<OutputStreamCallbackAidl> streamCb;
457 if (isOffload) {
458 streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
459 }
460 auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
461 if (isOffload) {
462 args.offloadInfo = aidlConfig.offloadInfo;
463 args.callback = streamCb;
464 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800465 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800466 args.eventCallback = eventCb;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800467 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
468 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800469 StreamContextAidl context(ret.desc, isOffload);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800470 if (!context.isValid()) {
471 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
472 __func__, ret.desc.toString().c_str());
473 return NO_INIT;
474 }
475 *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), nominalLatency,
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800476 std::move(ret.stream), this /*callbackBroker*/);
477 void* cbCookie = (*outStream).get();
478 {
479 std::lock_guard l(mLock);
480 mCallbacks.emplace(cbCookie, Callbacks{});
481 }
482 if (streamCb) streamCb->setCookie(cbCookie);
483 eventCb->setCookie(cbCookie);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800484 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000485 return OK;
486}
487
Mikhail Naganov31d46652023-01-10 18:29:25 +0000488status_t DeviceHalAidl::openInputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800489 audio_io_handle_t handle, audio_devices_t devices,
490 struct audio_config* config, audio_input_flags_t flags,
491 const char* address, audio_source_t source,
492 audio_devices_t outputDevice, const char* outputDeviceAddress,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000493 sp<StreamInHalInterface>* inStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800494 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000495 if (!inStream || !config) {
496 return BAD_VALUE;
497 }
498 TIME_CHECK();
499 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800500 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
501 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
502 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
503 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
504 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
505 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
506 int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
507 ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
508 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
509 AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
510 ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
511 AudioPortConfig mixPortConfig;
512 Cleanups cleanups;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800513 int32_t nominalLatency;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800514 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, aidlSource,
515 config, &cleanups, &aidlConfig, &mixPortConfig, &nominalLatency));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800516 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
517 args.portConfigId = mixPortConfig.id;
518 RecordTrackMetadata aidlTrackMetadata{
519 .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
520 if (outputDevice != AUDIO_DEVICE_NONE) {
521 aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
522 ::aidl::android::legacy2aidl_audio_device_AudioDevice(
523 outputDevice, outputDeviceAddress));
524 }
525 args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
526 args.bufferSizeFrames = aidlConfig.frameCount;
527 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
528 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800529 StreamContextAidl context(ret.desc, false /*isAsynchronous*/);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800530 if (!context.isValid()) {
531 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
532 __func__, ret.desc.toString().c_str());
533 return NO_INIT;
534 }
535 *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), nominalLatency,
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800536 std::move(ret.stream), this /*micInfoProvider*/);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800537 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000538 return OK;
539}
540
541status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
542 *supportsPatches = true;
543 return OK;
544}
545
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800546status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
547 const struct audio_port_config* sources,
548 unsigned int num_sinks,
549 const struct audio_port_config* sinks,
550 audio_patch_handle_t* patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800551 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000552 TIME_CHECK();
553 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800554 if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
555 sources == nullptr || sinks == nullptr || patch == nullptr) {
556 return BAD_VALUE;
557 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800558 // When the patch handle (*patch) is AUDIO_PATCH_HANDLE_NONE, it means
559 // the framework wants to create a new patch. The handle has to be generated
560 // by the HAL. Since handles generated this way can only be unique within
561 // a HAL module, the framework generates a globally unique handle, and maps
562 // it on the <HAL module, patch handle> pair.
563 // When the patch handle is set, it meant the framework intends to update
564 // an existing patch.
565 //
566 // This behavior corresponds to HAL module behavior, with the only difference
567 // that the HAL module uses `int32_t` for patch IDs. The following assert ensures
568 // that both the framework and the HAL use the same value for "no ID":
569 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
570 int32_t halPatchId = static_cast<int32_t>(*patch);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800571
572 // Upon conversion, mix port configs contain audio configuration, while
573 // device port configs contain device address. This data is used to find
574 // or create HAL configs.
575 std::vector<AudioPortConfig> aidlSources, aidlSinks;
576 for (unsigned int i = 0; i < num_sources; ++i) {
577 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
578 sources[i].role, sources[i].type)) ==
579 ::aidl::android::AudioPortDirection::INPUT;
580 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
581 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
582 sources[i], isInput, 0)));
583 }
584 for (unsigned int i = 0; i < num_sinks; ++i) {
585 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
586 sinks[i].role, sinks[i].type)) ==
587 ::aidl::android::AudioPortDirection::INPUT;
588 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
589 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
590 sinks[i], isInput, 0)));
591 }
592 Cleanups cleanups;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800593 auto existingPatchIt = halPatchId != 0 ? mPatches.find(halPatchId): mPatches.end();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800594 AudioPatch aidlPatch;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800595 if (existingPatchIt != mPatches.end()) {
596 aidlPatch = existingPatchIt->second;
597 aidlPatch.sourcePortConfigIds.clear();
598 aidlPatch.sinkPortConfigIds.clear();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800599 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800600 ALOGD("%s: sources: %s, sinks: %s",
601 __func__, ::android::internal::ToString(aidlSources).c_str(),
602 ::android::internal::ToString(aidlSinks).c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800603 auto fillPortConfigs = [&](
604 const std::vector<AudioPortConfig>& configs, std::vector<int32_t>* ids) -> status_t {
605 for (const auto& s : configs) {
606 AudioPortConfig portConfig;
607 bool created = false;
608 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(s, &portConfig, &created));
609 if (created) {
610 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, portConfig.id);
611 }
612 ids->push_back(portConfig.id);
613 }
614 return OK;
615 };
616 RETURN_STATUS_IF_ERROR(fillPortConfigs(aidlSources, &aidlPatch.sourcePortConfigIds));
617 RETURN_STATUS_IF_ERROR(fillPortConfigs(aidlSinks, &aidlPatch.sinkPortConfigIds));
618 if (existingPatchIt != mPatches.end()) {
619 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
620 mModule->setAudioPatch(aidlPatch, &aidlPatch)));
621 existingPatchIt->second = aidlPatch;
622 } else {
623 bool created = false;
624 RETURN_STATUS_IF_ERROR(findOrCreatePatch(aidlPatch, &aidlPatch, &created));
625 // Since no cleanup of the patch is needed, 'created' is ignored.
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800626 halPatchId = aidlPatch.id;
627 *patch = static_cast<audio_patch_handle_t>(halPatchId);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800628 }
629 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000630 return OK;
631}
632
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800633status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800634 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000635 TIME_CHECK();
636 if (!mModule) return NO_INIT;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800637 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
638 if (patch == AUDIO_PATCH_HANDLE_NONE) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800639 return BAD_VALUE;
640 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800641 int32_t halPatchId = static_cast<int32_t>(patch);
642 auto patchIt = mPatches.find(halPatchId);
643 if (patchIt == mPatches.end()) {
644 ALOGE("%s: patch with id %d not found", __func__, halPatchId);
645 return BAD_VALUE;
646 }
647 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->resetAudioPatch(halPatchId)));
648 mPatches.erase(patchIt);
Shunkai Yao51202502022-12-12 06:11:46 +0000649 return OK;
650}
651
Mikhail Naganov31d46652023-01-10 18:29:25 +0000652status_t DeviceHalAidl::getAudioPort(struct audio_port* port __unused) {
653 TIME_CHECK();
654 ALOGE("%s not implemented yet", __func__);
655 return INVALID_OPERATION;
656}
657
658status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port __unused) {
659 TIME_CHECK();
660 ALOGE("%s not implemented yet", __func__);
661 return INVALID_OPERATION;
662}
663
664status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config __unused) {
665 TIME_CHECK();
666 if (!mModule) return NO_INIT;
667 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000668 return OK;
669}
670
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800671MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
672 if (mMicrophones.status == Microphones::Status::UNKNOWN) {
673 TIME_CHECK();
674 std::vector<MicrophoneInfo> aidlInfo;
675 status_t status = statusTFromBinderStatus(mModule->getMicrophones(&aidlInfo));
676 if (status == OK) {
677 mMicrophones.status = Microphones::Status::QUERIED;
678 mMicrophones.info = std::move(aidlInfo);
679 } else if (status == INVALID_OPERATION) {
680 mMicrophones.status = Microphones::Status::NOT_SUPPORTED;
681 } else {
682 ALOGE("%s: Unexpected status from 'IModule.getMicrophones': %d", __func__, status);
683 return {};
684 }
685 }
686 if (mMicrophones.status == Microphones::Status::QUERIED) {
687 return &mMicrophones.info;
688 }
689 return {}; // NOT_SUPPORTED
690}
691
Shunkai Yao51202502022-12-12 06:11:46 +0000692status_t DeviceHalAidl::getMicrophones(
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800693 std::vector<audio_microphone_characteristic_t>* microphones) {
694 if (!microphones) {
695 return BAD_VALUE;
696 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000697 TIME_CHECK();
698 if (!mModule) return NO_INIT;
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800699 auto staticInfo = getMicrophoneInfo();
700 if (!staticInfo) return INVALID_OPERATION;
701 std::vector<MicrophoneDynamicInfo> emptyDynamicInfo;
702 emptyDynamicInfo.reserve(staticInfo->size());
703 std::transform(staticInfo->begin(), staticInfo->end(), std::back_inserter(emptyDynamicInfo),
704 [](const auto& info) { return MicrophoneDynamicInfo{ .id = info.id }; });
705 *microphones = VALUE_OR_RETURN_STATUS(
706 ::aidl::android::convertContainers<std::vector<audio_microphone_characteristic_t>>(
707 *staticInfo, emptyDynamicInfo,
708 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t)
709 );
Shunkai Yao51202502022-12-12 06:11:46 +0000710 return OK;
711}
712
Mikhail Naganov31d46652023-01-10 18:29:25 +0000713status_t DeviceHalAidl::addDeviceEffect(audio_port_handle_t device __unused,
714 sp<EffectHalInterface> effect) {
Shunkai Yao51202502022-12-12 06:11:46 +0000715 if (!effect) {
716 return BAD_VALUE;
717 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000718 TIME_CHECK();
719 if (!mModule) return NO_INIT;
720 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000721 return OK;
722}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000723status_t DeviceHalAidl::removeDeviceEffect(audio_port_handle_t device __unused,
Shunkai Yao51202502022-12-12 06:11:46 +0000724 sp<EffectHalInterface> effect) {
725 if (!effect) {
726 return BAD_VALUE;
727 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000728 TIME_CHECK();
729 if (!mModule) return NO_INIT;
730 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000731 return OK;
732}
733
734status_t DeviceHalAidl::getMmapPolicyInfos(
735 media::audio::common::AudioMMapPolicyType policyType __unused,
736 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos __unused) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000737 TIME_CHECK();
Shunkai Yao51202502022-12-12 06:11:46 +0000738 ALOGE("%s not implemented yet", __func__);
739 return OK;
740}
741
742int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000743 TIME_CHECK();
Shunkai Yao51202502022-12-12 06:11:46 +0000744 ALOGE("%s not implemented yet", __func__);
745 return OK;
746}
747
748int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000749 TIME_CHECK();
Shunkai Yao51202502022-12-12 06:11:46 +0000750 ALOGE("%s not implemented yet", __func__);
751 return OK;
752}
753
754error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000755 TIME_CHECK();
Shunkai Yao51202502022-12-12 06:11:46 +0000756 ALOGE("%s not implemented yet", __func__);
757 return base::unexpected(INVALID_OPERATION);
758}
759
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000760status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
761 TIME_CHECK();
762 if (!mModule) return NO_INIT;
763 return mModule->dump(fd, Args(args).args(), args.size());
Shunkai Yao51202502022-12-12 06:11:46 +0000764};
765
Mikhail Naganov31d46652023-01-10 18:29:25 +0000766int32_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports __unused) {
767 TIME_CHECK();
Shunkai Yao51202502022-12-12 06:11:46 +0000768 ALOGE("%s not implemented yet", __func__);
769 return INVALID_OPERATION;
770}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000771
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800772bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
773 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
774 return p.ext.get<AudioPortExt::Tag::device>().device == device;
775}
776
777bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
778 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
779 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
780 return p.portId == mDefaultInputPortId;
781 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
782 return p.portId == mDefaultOutputPortId;
783 }
784 return p.ext.get<AudioPortExt::Tag::device>().device == device;
785}
786
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800787status_t DeviceHalAidl::createPortConfig(
788 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800789 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800790 AudioPortConfig appliedPortConfig;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800791 bool applied = false;
792 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800793 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800794 if (!applied) {
795 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800796 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800797 if (!applied) {
798 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800799 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800800 return NO_INIT;
801 }
802 }
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800803 auto id = appliedPortConfig.id;
804 auto [it, inserted] = mPortConfigs.emplace(std::move(id), std::move(appliedPortConfig));
805 LOG_ALWAYS_FATAL_IF(!inserted, "%s: port config with id %d already exists",
806 __func__, it->first);
807 *result = it;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800808 return OK;
809}
810
811status_t DeviceHalAidl::findOrCreatePatch(
812 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
813 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
814 requestedPatch.sourcePortConfigIds.end());
815 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
816 requestedPatch.sinkPortConfigIds.end());
817 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
818}
819
820status_t DeviceHalAidl::findOrCreatePatch(
821 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
822 AudioPatch* patch, bool* created) {
823 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
824 if (patchIt == mPatches.end()) {
825 TIME_CHECK();
826 AudioPatch requestedPatch, appliedPatch;
827 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
828 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
829 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
830 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
831 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
832 requestedPatch, &appliedPatch)));
833 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
834 *created = true;
835 } else {
836 *created = false;
837 }
838 *patch = patchIt->second;
839 return OK;
840}
841
842status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device,
843 AudioPortConfig* portConfig, bool* created) {
844 auto portConfigIt = findPortConfig(device);
845 if (portConfigIt == mPortConfigs.end()) {
846 auto portsIt = findPort(device);
847 if (portsIt == mPorts.end()) {
848 ALOGE("%s: device port for device %s is not found in the module %s",
849 __func__, device.toString().c_str(), mInstance.c_str());
850 return BAD_VALUE;
851 }
852 AudioPortConfig requestedPortConfig;
853 requestedPortConfig.portId = portsIt->first;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800854 RETURN_STATUS_IF_ERROR(createPortConfig(requestedPortConfig, &portConfigIt));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800855 *created = true;
856 } else {
857 *created = false;
858 }
859 *portConfig = portConfigIt->second;
860 return OK;
861}
862
863status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800864 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800865 AudioSource source, AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800866 // These flags get removed one by one in this order when retrying port finding.
867 static const std::vector<AudioInputFlags> kOptionalInputFlags{
868 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800869 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800870 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800871 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
872 AudioIoFlags matchFlags = flags.value();
873 auto portsIt = findPort(config, matchFlags);
874 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
875 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
876 if (!isBitPositionFlagSet(
877 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
878 ++optionalInputFlagsIt;
879 continue;
880 }
881 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
882 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
883 portsIt = findPort(config, matchFlags);
884 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
885 "retried with flags %s", __func__, config.toString().c_str(),
886 flags.value().toString().c_str(), mInstance.c_str(),
887 matchFlags.toString().c_str());
888 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800889 if (portsIt == mPorts.end()) {
890 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800891 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800892 mInstance.c_str());
893 return BAD_VALUE;
894 }
895 AudioPortConfig requestedPortConfig;
896 requestedPortConfig.portId = portsIt->first;
897 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800898 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800899 if (matchFlags.getTag() == AudioIoFlags::Tag::input
900 && source != AudioSource::SYS_RESERVED_INVALID) {
901 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
902 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
903 }
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800904 RETURN_STATUS_IF_ERROR(createPortConfig(requestedPortConfig, &portConfigIt));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800905 *created = true;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800906 } else if (!flags.has_value()) {
907 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
908 "and was not created as flags are not specified",
909 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
910 return BAD_VALUE;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800911 } else {
912 *created = false;
913 }
914 *portConfig = portConfigIt->second;
915 return OK;
916}
917
918status_t DeviceHalAidl::findOrCreatePortConfig(
919 const AudioPortConfig& requestedPortConfig, AudioPortConfig* portConfig, bool* created) {
920 using Tag = AudioPortExt::Tag;
921 if (requestedPortConfig.ext.getTag() == Tag::mix) {
922 if (const auto& p = requestedPortConfig;
923 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800924 !p.format.has_value()) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800925 ALOGW("%s: provided mix port config is not fully specified: %s",
926 __func__, p.toString().c_str());
927 return BAD_VALUE;
928 }
929 AudioConfig config;
930 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800931 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
932 AudioPortMixExtUseCase::Tag::source ?
933 requestedPortConfig.ext.get<Tag::mix>().usecase.
934 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800935 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800936 requestedPortConfig.ext.get<Tag::mix>().handle, source, portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800937 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
938 return findOrCreatePortConfig(
939 requestedPortConfig.ext.get<Tag::device>().device, portConfig, created);
940 }
941 ALOGW("%s: unsupported audio port config: %s",
942 __func__, requestedPortConfig.toString().c_str());
943 return BAD_VALUE;
944}
945
946DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
947 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
948 return std::find_if(mPatches.begin(), mPatches.end(),
949 [&](const auto& pair) {
950 const auto& p = pair.second;
951 std::set<int32_t> patchSrcs(
952 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
953 std::set<int32_t> patchSinks(
954 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
955 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
956}
957
958DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800959 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
960 return mPorts.find(mDefaultInputPortId);
961 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
962 return mPorts.find(mDefaultOutputPortId);
963 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800964 return std::find_if(mPorts.begin(), mPorts.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800965 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800966}
967
968DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
969 const AudioConfig& config, const AudioIoFlags& flags) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800970 auto matcher = [&](const auto& pair) {
971 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800972 return p.ext.getTag() == AudioPortExt::Tag::mix &&
973 p.flags == flags &&
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800974 std::find_if(p.profiles.begin(), p.profiles.end(),
975 [&](const auto& prof) {
976 return prof.format == config.base.format &&
977 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
978 config.base.channelMask) != prof.channelMasks.end() &&
979 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
980 config.base.sampleRate) != prof.sampleRates.end();
981 }) != p.profiles.end(); };
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800982 return std::find_if(mPorts.begin(), mPorts.end(), matcher);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800983}
984
985DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800986 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800987 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800988}
989
990DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800991 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800992 using Tag = AudioPortExt::Tag;
993 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
994 [&](const auto& pair) {
995 const auto& p = pair.second;
996 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
997 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
998 !p.format.has_value() || !p.flags.has_value(),
999 "%s: stored mix port config is not fully specified: %s",
1000 __func__, p.toString().c_str());
1001 return p.ext.getTag() == Tag::mix &&
1002 isConfigEqualToPortConfig(config, p) &&
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001003 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001004 p.ext.template get<Tag::mix>().handle == ioHandle; });
1005}
1006/*
1007DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
1008 const AudioPortConfig& portConfig) {
1009 using Tag = AudioPortExt::Tag;
1010 if (portConfig.ext.getTag() == Tag::mix) {
1011 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
1012 [&](const auto& pair) {
1013 const auto& p = pair.second;
1014 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
1015 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
1016 !p.format.has_value() || !p.flags.has_value(),
1017 "%s: stored mix port config is not fully specified: %s",
1018 __func__, p.toString().c_str());
1019 return p.ext.getTag() == Tag::mix &&
1020 (!portConfig.sampleRate.has_value() ||
1021 p.sampleRate == portConfig.sampleRate) &&
1022 (!portConfig.channelMask.has_value() ||
1023 p.channelMask == portConfig.channelMask) &&
1024 (!portConfig.format.has_value() || p.format == portConfig.format) &&
1025 (!portConfig.flags.has_value() || p.flags == portConfig.flags) &&
1026 p.ext.template get<Tag::mix>().handle ==
1027 portConfig.ext.template get<Tag::mix>().handle; });
1028 } else if (portConfig.ext.getTag() == Tag::device) {
1029 return findPortConfig(portConfig.ext.get<Tag::device>().device);
1030 }
1031 return mPortConfigs.end();
1032}
1033*/
1034void DeviceHalAidl::resetPatch(int32_t patchId) {
1035 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1036 mPatches.erase(it);
1037 TIME_CHECK();
1038 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1039 ALOGE("%s: error while resetting patch %d: %s",
1040 __func__, patchId, status.getDescription().c_str());
1041 }
1042 return;
1043 }
1044 ALOGE("%s: patch id %d not found", __func__, patchId);
1045}
1046
1047void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1048 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1049 mPortConfigs.erase(it);
1050 TIME_CHECK();
1051 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1052 !status.isOk()) {
1053 ALOGE("%s: error while resetting port config %d: %s",
1054 __func__, portConfigId, status.getDescription().c_str());
1055 }
1056 return;
1057 }
1058 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1059}
1060
Mikhail Naganovdfd594e2023-02-08 16:59:41 -08001061void DeviceHalAidl::clearCallbacks(void* cookie) {
1062 std::lock_guard l(mLock);
1063 mCallbacks.erase(cookie);
1064}
1065
1066sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1067 return getCallbackImpl(cookie, &Callbacks::out);
1068}
1069
1070void DeviceHalAidl::setStreamOutCallback(
1071 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1072 setCallbackImpl(cookie, &Callbacks::out, cb);
1073}
1074
1075sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1076 void* cookie) {
1077 return getCallbackImpl(cookie, &Callbacks::event);
1078}
1079
1080void DeviceHalAidl::setStreamOutEventCallback(
1081 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1082 setCallbackImpl(cookie, &Callbacks::event, cb);
1083}
1084
1085sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1086 void* cookie) {
1087 return getCallbackImpl(cookie, &Callbacks::latency);
1088}
1089
1090void DeviceHalAidl::setStreamOutLatencyModeCallback(
1091 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1092 setCallbackImpl(cookie, &Callbacks::latency, cb);
1093}
1094
1095template<class C>
1096sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1097 std::lock_guard l(mLock);
1098 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1099 return ((it->second).*field).promote();
1100 }
1101 return nullptr;
1102}
1103template<class C>
1104void DeviceHalAidl::setCallbackImpl(
1105 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1106 std::lock_guard l(mLock);
1107 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1108 (it->second).*field = cb;
1109 }
1110}
1111
Mikhail Naganov31d46652023-01-10 18:29:25 +00001112} // namespace android