blob: 8b88f249164b2dfa70586acfdeb7b1f3256b2d42 [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();
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700756 if (!mModule) return NO_INIT;
757 int32_t aidlHwAvSync;
758 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
759 return VALUE_OR_RETURN_STATUS(
760 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +0000761}
762
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000763status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
764 TIME_CHECK();
765 if (!mModule) return NO_INIT;
766 return mModule->dump(fd, Args(args).args(), args.size());
Shunkai Yao51202502022-12-12 06:11:46 +0000767};
768
Mikhail Naganov31d46652023-01-10 18:29:25 +0000769int32_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports __unused) {
770 TIME_CHECK();
Shunkai Yao51202502022-12-12 06:11:46 +0000771 ALOGE("%s not implemented yet", __func__);
772 return INVALID_OPERATION;
773}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000774
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800775bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
776 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
777 return p.ext.get<AudioPortExt::Tag::device>().device == device;
778}
779
780bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
781 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
782 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
783 return p.portId == mDefaultInputPortId;
784 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
785 return p.portId == mDefaultOutputPortId;
786 }
787 return p.ext.get<AudioPortExt::Tag::device>().device == device;
788}
789
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800790status_t DeviceHalAidl::createPortConfig(
791 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800792 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800793 AudioPortConfig appliedPortConfig;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800794 bool applied = false;
795 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800796 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800797 if (!applied) {
798 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800799 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800800 if (!applied) {
801 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800802 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800803 return NO_INIT;
804 }
805 }
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800806 auto id = appliedPortConfig.id;
807 auto [it, inserted] = mPortConfigs.emplace(std::move(id), std::move(appliedPortConfig));
808 LOG_ALWAYS_FATAL_IF(!inserted, "%s: port config with id %d already exists",
809 __func__, it->first);
810 *result = it;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800811 return OK;
812}
813
814status_t DeviceHalAidl::findOrCreatePatch(
815 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
816 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
817 requestedPatch.sourcePortConfigIds.end());
818 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
819 requestedPatch.sinkPortConfigIds.end());
820 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
821}
822
823status_t DeviceHalAidl::findOrCreatePatch(
824 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
825 AudioPatch* patch, bool* created) {
826 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
827 if (patchIt == mPatches.end()) {
828 TIME_CHECK();
829 AudioPatch requestedPatch, appliedPatch;
830 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
831 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
832 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
833 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
834 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
835 requestedPatch, &appliedPatch)));
836 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
837 *created = true;
838 } else {
839 *created = false;
840 }
841 *patch = patchIt->second;
842 return OK;
843}
844
845status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device,
846 AudioPortConfig* portConfig, bool* created) {
847 auto portConfigIt = findPortConfig(device);
848 if (portConfigIt == mPortConfigs.end()) {
849 auto portsIt = findPort(device);
850 if (portsIt == mPorts.end()) {
851 ALOGE("%s: device port for device %s is not found in the module %s",
852 __func__, device.toString().c_str(), mInstance.c_str());
853 return BAD_VALUE;
854 }
855 AudioPortConfig requestedPortConfig;
856 requestedPortConfig.portId = portsIt->first;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800857 RETURN_STATUS_IF_ERROR(createPortConfig(requestedPortConfig, &portConfigIt));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800858 *created = true;
859 } else {
860 *created = false;
861 }
862 *portConfig = portConfigIt->second;
863 return OK;
864}
865
866status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800867 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800868 AudioSource source, AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800869 // These flags get removed one by one in this order when retrying port finding.
870 static const std::vector<AudioInputFlags> kOptionalInputFlags{
871 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800872 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800873 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800874 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
875 AudioIoFlags matchFlags = flags.value();
876 auto portsIt = findPort(config, matchFlags);
877 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
878 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
879 if (!isBitPositionFlagSet(
880 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
881 ++optionalInputFlagsIt;
882 continue;
883 }
884 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
885 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
886 portsIt = findPort(config, matchFlags);
887 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
888 "retried with flags %s", __func__, config.toString().c_str(),
889 flags.value().toString().c_str(), mInstance.c_str(),
890 matchFlags.toString().c_str());
891 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800892 if (portsIt == mPorts.end()) {
893 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800894 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800895 mInstance.c_str());
896 return BAD_VALUE;
897 }
898 AudioPortConfig requestedPortConfig;
899 requestedPortConfig.portId = portsIt->first;
900 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800901 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800902 if (matchFlags.getTag() == AudioIoFlags::Tag::input
903 && source != AudioSource::SYS_RESERVED_INVALID) {
904 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
905 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
906 }
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800907 RETURN_STATUS_IF_ERROR(createPortConfig(requestedPortConfig, &portConfigIt));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800908 *created = true;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800909 } else if (!flags.has_value()) {
910 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
911 "and was not created as flags are not specified",
912 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
913 return BAD_VALUE;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800914 } else {
915 *created = false;
916 }
917 *portConfig = portConfigIt->second;
918 return OK;
919}
920
921status_t DeviceHalAidl::findOrCreatePortConfig(
922 const AudioPortConfig& requestedPortConfig, AudioPortConfig* portConfig, bool* created) {
923 using Tag = AudioPortExt::Tag;
924 if (requestedPortConfig.ext.getTag() == Tag::mix) {
925 if (const auto& p = requestedPortConfig;
926 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800927 !p.format.has_value()) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800928 ALOGW("%s: provided mix port config is not fully specified: %s",
929 __func__, p.toString().c_str());
930 return BAD_VALUE;
931 }
932 AudioConfig config;
933 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800934 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
935 AudioPortMixExtUseCase::Tag::source ?
936 requestedPortConfig.ext.get<Tag::mix>().usecase.
937 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800938 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800939 requestedPortConfig.ext.get<Tag::mix>().handle, source, portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800940 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
941 return findOrCreatePortConfig(
942 requestedPortConfig.ext.get<Tag::device>().device, portConfig, created);
943 }
944 ALOGW("%s: unsupported audio port config: %s",
945 __func__, requestedPortConfig.toString().c_str());
946 return BAD_VALUE;
947}
948
949DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
950 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
951 return std::find_if(mPatches.begin(), mPatches.end(),
952 [&](const auto& pair) {
953 const auto& p = pair.second;
954 std::set<int32_t> patchSrcs(
955 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
956 std::set<int32_t> patchSinks(
957 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
958 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
959}
960
961DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800962 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
963 return mPorts.find(mDefaultInputPortId);
964 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
965 return mPorts.find(mDefaultOutputPortId);
966 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800967 return std::find_if(mPorts.begin(), mPorts.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800968 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800969}
970
971DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
972 const AudioConfig& config, const AudioIoFlags& flags) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800973 auto matcher = [&](const auto& pair) {
974 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800975 return p.ext.getTag() == AudioPortExt::Tag::mix &&
976 p.flags == flags &&
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800977 std::find_if(p.profiles.begin(), p.profiles.end(),
978 [&](const auto& prof) {
979 return prof.format == config.base.format &&
980 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
981 config.base.channelMask) != prof.channelMasks.end() &&
982 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
983 config.base.sampleRate) != prof.sampleRates.end();
984 }) != p.profiles.end(); };
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800985 return std::find_if(mPorts.begin(), mPorts.end(), matcher);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800986}
987
988DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800989 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800990 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800991}
992
993DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800994 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800995 using Tag = AudioPortExt::Tag;
996 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
997 [&](const auto& pair) {
998 const auto& p = pair.second;
999 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
1000 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
1001 !p.format.has_value() || !p.flags.has_value(),
1002 "%s: stored mix port config is not fully specified: %s",
1003 __func__, p.toString().c_str());
1004 return p.ext.getTag() == Tag::mix &&
1005 isConfigEqualToPortConfig(config, p) &&
Mikhail Naganov89a9f742023-01-30 12:33:18 -08001006 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganov5b1eed12023-01-25 11:29:11 -08001007 p.ext.template get<Tag::mix>().handle == ioHandle; });
1008}
1009/*
1010DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
1011 const AudioPortConfig& portConfig) {
1012 using Tag = AudioPortExt::Tag;
1013 if (portConfig.ext.getTag() == Tag::mix) {
1014 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
1015 [&](const auto& pair) {
1016 const auto& p = pair.second;
1017 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
1018 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
1019 !p.format.has_value() || !p.flags.has_value(),
1020 "%s: stored mix port config is not fully specified: %s",
1021 __func__, p.toString().c_str());
1022 return p.ext.getTag() == Tag::mix &&
1023 (!portConfig.sampleRate.has_value() ||
1024 p.sampleRate == portConfig.sampleRate) &&
1025 (!portConfig.channelMask.has_value() ||
1026 p.channelMask == portConfig.channelMask) &&
1027 (!portConfig.format.has_value() || p.format == portConfig.format) &&
1028 (!portConfig.flags.has_value() || p.flags == portConfig.flags) &&
1029 p.ext.template get<Tag::mix>().handle ==
1030 portConfig.ext.template get<Tag::mix>().handle; });
1031 } else if (portConfig.ext.getTag() == Tag::device) {
1032 return findPortConfig(portConfig.ext.get<Tag::device>().device);
1033 }
1034 return mPortConfigs.end();
1035}
1036*/
1037void DeviceHalAidl::resetPatch(int32_t patchId) {
1038 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1039 mPatches.erase(it);
1040 TIME_CHECK();
1041 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1042 ALOGE("%s: error while resetting patch %d: %s",
1043 __func__, patchId, status.getDescription().c_str());
1044 }
1045 return;
1046 }
1047 ALOGE("%s: patch id %d not found", __func__, patchId);
1048}
1049
1050void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1051 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1052 mPortConfigs.erase(it);
1053 TIME_CHECK();
1054 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1055 !status.isOk()) {
1056 ALOGE("%s: error while resetting port config %d: %s",
1057 __func__, portConfigId, status.getDescription().c_str());
1058 }
1059 return;
1060 }
1061 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1062}
1063
Mikhail Naganovdfd594e2023-02-08 16:59:41 -08001064void DeviceHalAidl::clearCallbacks(void* cookie) {
1065 std::lock_guard l(mLock);
1066 mCallbacks.erase(cookie);
1067}
1068
1069sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1070 return getCallbackImpl(cookie, &Callbacks::out);
1071}
1072
1073void DeviceHalAidl::setStreamOutCallback(
1074 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1075 setCallbackImpl(cookie, &Callbacks::out, cb);
1076}
1077
1078sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1079 void* cookie) {
1080 return getCallbackImpl(cookie, &Callbacks::event);
1081}
1082
1083void DeviceHalAidl::setStreamOutEventCallback(
1084 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1085 setCallbackImpl(cookie, &Callbacks::event, cb);
1086}
1087
1088sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1089 void* cookie) {
1090 return getCallbackImpl(cookie, &Callbacks::latency);
1091}
1092
1093void DeviceHalAidl::setStreamOutLatencyModeCallback(
1094 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1095 setCallbackImpl(cookie, &Callbacks::latency, cb);
1096}
1097
1098template<class C>
1099sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1100 std::lock_guard l(mLock);
1101 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1102 return ((it->second).*field).promote();
1103 }
1104 return nullptr;
1105}
1106template<class C>
1107void DeviceHalAidl::setCallbackImpl(
1108 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1109 std::lock_guard l(mLock);
1110 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1111 (it->second).*field = cb;
1112 }
1113}
1114
Mikhail Naganov31d46652023-01-10 18:29:25 +00001115} // namespace android