blob: 9ce16891b28db43e67e6a1e38141c4bc72f082a2 [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 Naganov5b1eed12023-01-25 11:29:11 -080057using aidl::android::hardware::audio::common::RecordTrackMetadata;
58using aidl::android::hardware::audio::core::AudioPatch;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000059using aidl::android::hardware::audio::core::IModule;
60using aidl::android::hardware::audio::core::ITelephony;
61using aidl::android::hardware::audio::core::StreamDescriptor;
Mikhail Naganov31d46652023-01-10 18:29:25 +000062
63namespace android {
64
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080065namespace {
66
67bool isConfigEqualToPortConfig(const AudioConfig& config, const AudioPortConfig& portConfig) {
68 return portConfig.sampleRate.value().value == config.base.sampleRate &&
69 portConfig.channelMask.value() == config.base.channelMask &&
70 portConfig.format.value() == config.base.format;
71}
72
73void setConfigFromPortConfig(AudioConfig* config, const AudioPortConfig& portConfig) {
74 config->base.sampleRate = portConfig.sampleRate.value().value;
75 config->base.channelMask = portConfig.channelMask.value();
76 config->base.format = portConfig.format.value();
77}
78
79void setPortConfigFromConfig(AudioPortConfig* portConfig, const AudioConfig& config) {
80 portConfig->sampleRate = Int{ .value = config.base.sampleRate };
81 portConfig->channelMask = config.base.channelMask;
82 portConfig->format = config.base.format;
83}
84
85} // namespace
86
Mikhail Naganov31d46652023-01-10 18:29:25 +000087status_t DeviceHalAidl::getSupportedDevices(uint32_t*) {
88 // Obsolete.
89 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +000090}
91
92status_t DeviceHalAidl::initCheck() {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080093 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +000094 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080095 std::vector<AudioPort> ports;
96 RETURN_STATUS_IF_ERROR(
97 statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
98 ALOGW_IF(ports.empty(), "%s: module %s returned an empty list of audio ports",
99 __func__, mInstance.c_str());
100 std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()),
101 [](const auto& p) { return std::make_pair(p.id, p); });
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800102 mDefaultInputPortId = mDefaultOutputPortId = -1;
103 const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
104 for (const auto& pair : mPorts) {
105 const auto& p = pair.second;
106 if (p.ext.getTag() == AudioPortExt::Tag::device &&
107 (p.ext.get<AudioPortExt::Tag::device>().flags & defaultDeviceFlag) != 0) {
108 if (p.flags.getTag() == AudioIoFlags::Tag::input) {
109 mDefaultInputPortId = p.id;
110 } else if (p.flags.getTag() == AudioIoFlags::Tag::output) {
111 mDefaultOutputPortId = p.id;
112 }
113 }
114 }
115 ALOGI("%s: module %s default port ids: input %d, output %d",
116 __func__, mInstance.c_str(), mDefaultInputPortId, mDefaultOutputPortId);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800117 std::vector<AudioPortConfig> portConfigs;
118 RETURN_STATUS_IF_ERROR(
119 statusTFromBinderStatus(mModule->getAudioPortConfigs(&portConfigs))); // OK if empty
120 std::transform(portConfigs.begin(), portConfigs.end(),
121 std::inserter(mPortConfigs, mPortConfigs.end()),
122 [](const auto& p) { return std::make_pair(p.id, p); });
123 std::vector<AudioPatch> patches;
124 RETURN_STATUS_IF_ERROR(
125 statusTFromBinderStatus(mModule->getAudioPatches(&patches))); // OK if empty
126 std::transform(patches.begin(), patches.end(),
127 std::inserter(mPatches, mPatches.end()),
128 [](const auto& p) { return std::make_pair(p.id, p); });
Shunkai Yao51202502022-12-12 06:11:46 +0000129 return OK;
130}
131
132status_t DeviceHalAidl::setVoiceVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000133 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000134 if (!mModule) return NO_INIT;
135 std::shared_ptr<ITelephony> telephony;
136 if (ndk::ScopedAStatus status = mModule->getTelephony(&telephony);
137 status.isOk() && telephony != nullptr) {
138 ITelephony::TelecomConfig inConfig{ .voiceVolume = Float{volume} }, outConfig;
139 RETURN_STATUS_IF_ERROR(
140 statusTFromBinderStatus(telephony->setTelecomConfig(inConfig, &outConfig)));
141 ALOGW_IF(outConfig.voiceVolume.has_value() && volume != outConfig.voiceVolume.value().value,
142 "%s: the resulting voice volume %f is not the same as requested %f",
143 __func__, outConfig.voiceVolume.value().value, volume);
144 }
145 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +0000146}
147
148status_t DeviceHalAidl::setMasterVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000149 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000150 if (!mModule) return NO_INIT;
151 return statusTFromBinderStatus(mModule->setMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000152}
153
154status_t DeviceHalAidl::getMasterVolume(float *volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000155 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000156 if (!mModule) return NO_INIT;
157 return statusTFromBinderStatus(mModule->getMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000158}
159
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000160status_t DeviceHalAidl::setMode(audio_mode_t mode) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000161 TIME_CHECK();
162 if (!mModule) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000163 AudioMode audioMode = VALUE_OR_FATAL(::aidl::android::legacy2aidl_audio_mode_t_AudioMode(mode));
164 std::shared_ptr<ITelephony> telephony;
165 if (ndk::ScopedAStatus status = mModule->getTelephony(&telephony);
166 status.isOk() && telephony != nullptr) {
167 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(telephony->switchAudioMode(audioMode)));
168 }
169 return statusTFromBinderStatus(mModule->updateAudioMode(audioMode));
Shunkai Yao51202502022-12-12 06:11:46 +0000170}
171
172status_t DeviceHalAidl::setMicMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000173 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000174 if (!mModule) return NO_INIT;
175 return statusTFromBinderStatus(mModule->setMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000176}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000177
Shunkai Yao51202502022-12-12 06:11:46 +0000178status_t DeviceHalAidl::getMicMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000179 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000180 if (!mModule) return NO_INIT;
181 return statusTFromBinderStatus(mModule->getMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000182}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000183
Shunkai Yao51202502022-12-12 06:11:46 +0000184status_t DeviceHalAidl::setMasterMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000185 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000186 if (!mModule) return NO_INIT;
187 return statusTFromBinderStatus(mModule->setMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000188}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000189
Shunkai Yao51202502022-12-12 06:11:46 +0000190status_t DeviceHalAidl::getMasterMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000191 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000192 if (!mModule) return NO_INIT;
193 return statusTFromBinderStatus(mModule->getMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000194}
195
Mikhail Naganov31d46652023-01-10 18:29:25 +0000196status_t DeviceHalAidl::setParameters(const String8& kvPairs __unused) {
197 TIME_CHECK();
198 if (!mModule) return NO_INIT;
199 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000200 return OK;
201}
202
Mikhail Naganov31d46652023-01-10 18:29:25 +0000203status_t DeviceHalAidl::getParameters(const String8& keys __unused, String8 *values) {
204 TIME_CHECK();
205 values->clear();
206 if (!mModule) return NO_INIT;
207 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000208 return OK;
209}
210
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800211namespace {
212
213class Cleanup {
214 public:
215 typedef void (DeviceHalAidl::*Cleaner)(int32_t);
216
217 Cleanup(DeviceHalAidl* device, Cleaner cleaner, int32_t id) :
218 mDevice(device), mCleaner(cleaner), mId(id) {}
219 ~Cleanup() { clean(); }
220 void clean() {
221 if (mDevice != nullptr) (mDevice->*mCleaner)(mId);
222 disarm();
223 }
224 void disarm() { mDevice = nullptr; }
225
226 private:
227 DeviceHalAidl* mDevice;
228 const Cleaner mCleaner;
229 const int32_t mId;
230};
231
232} // namespace
233
234// Since the order of container elements destruction is unspecified,
235// ensure that cleanups are performed from the most recent one and upwards.
236// This is the same as if there were individual Cleanup instances on the stack,
237// however the bonus is that we can disarm all of them with just one statement.
238class DeviceHalAidl::Cleanups : public std::forward_list<Cleanup> {
239 public:
240 ~Cleanups() { for (auto& c : *this) c.clean(); }
241 void disarmAll() { for (auto& c : *this) c.disarm(); }
242};
243
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800244status_t DeviceHalAidl::getInputBufferSize(const struct audio_config* config, size_t* size) {
245 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
246 if (size == nullptr) return BAD_VALUE;
247 TIME_CHECK();
248 if (!mModule) return NO_INIT;
249 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
250 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
251 AudioDevice aidlDevice;
252 aidlDevice.type.type = AudioDeviceType::IN_DEFAULT;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800253 AudioSource aidlSource = AudioSource::DEFAULT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800254 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
255 AudioPortConfig mixPortConfig;
256 Cleanups cleanups;
257 audio_config writableConfig = *config;
258 int32_t nominalLatency;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800259 RETURN_STATUS_IF_ERROR(prepareToOpenStream(0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
260 &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &nominalLatency));
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800261 *size = aidlConfig.frameCount *
262 getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
263 // Do not disarm cleanups to release temporary port configs.
264 return OK;
265}
266
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800267status_t DeviceHalAidl::prepareToOpenStream(
268 int32_t aidlHandle, const AudioDevice& aidlDevice, const AudioIoFlags& aidlFlags,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800269 AudioSource aidlSource, struct audio_config* config,
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800270 Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
271 int32_t* nominalLatency) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800272 const bool isInput = aidlFlags.getTag() == AudioIoFlags::Tag::input;
273 // Find / create AudioPortConfigs for the device port and the mix port,
274 // then find / create a patch between them, and open a stream on the mix port.
275 AudioPortConfig devicePortConfig;
276 bool created = false;
277 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, &devicePortConfig, &created));
278 if (created) {
279 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
280 }
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800281 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*aidlConfig, aidlFlags, aidlHandle, aidlSource,
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800282 mixPortConfig, &created));
283 if (created) {
284 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
285 }
286 setConfigFromPortConfig(aidlConfig, *mixPortConfig);
287 AudioPatch patch;
288 if (isInput) {
289 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
290 {devicePortConfig.id}, {mixPortConfig->id}, &patch, &created));
291 } else {
292 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
293 {mixPortConfig->id}, {devicePortConfig.id}, &patch, &created));
294 }
295 if (created) {
296 cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, patch.id);
297 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800298 *nominalLatency = patch.latenciesMs[0];
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800299 if (aidlConfig->frameCount <= 0) {
300 aidlConfig->frameCount = patch.minimumStreamBufferSizeFrames;
301 }
302 *config = VALUE_OR_RETURN_STATUS(
303 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(*aidlConfig, isInput));
304 return OK;
305}
306
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800307namespace {
308
309class StreamCallbackBase {
310 protected:
311 explicit StreamCallbackBase(const sp<CallbackBroker>& broker) : mBroker(broker) {}
312 public:
313 void* getCookie() const { return mCookie; }
314 void setCookie(void* cookie) { mCookie = cookie; }
315 sp<CallbackBroker> getBroker() const {
316 if (void* cookie = mCookie; cookie != nullptr) return mBroker.promote();
317 return nullptr;
318 }
319 private:
320 const wp<CallbackBroker> mBroker;
321 std::atomic<void*> mCookie;
322};
323
324template<class C>
325class StreamCallbackBaseHelper {
326 protected:
327 explicit StreamCallbackBaseHelper(const StreamCallbackBase& base) : mBase(base) {}
328 sp<C> getCb(const sp<CallbackBroker>& broker, void* cookie);
329 using CbRef = const sp<C>&;
330 ndk::ScopedAStatus runCb(const std::function<void(CbRef cb)>& f) {
331 if (auto cb = getCb(mBase.getBroker(), mBase.getCookie()); cb != nullptr) f(cb);
332 return ndk::ScopedAStatus::ok();
333 }
334 private:
335 const StreamCallbackBase& mBase;
336};
337
338template<>
339sp<StreamOutHalInterfaceCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>::getCb(
340 const sp<CallbackBroker>& broker, void* cookie) {
341 if (broker != nullptr) return broker->getStreamOutCallback(cookie);
342 return nullptr;
343}
344
345template<>
346sp<StreamOutHalInterfaceEventCallback>
347StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::getCb(
348 const sp<CallbackBroker>& broker, void* cookie) {
349 if (broker != nullptr) return broker->getStreamOutEventCallback(cookie);
350 return nullptr;
351}
352
353template<>
354sp<StreamOutHalInterfaceLatencyModeCallback>
355StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::getCb(
356 const sp<CallbackBroker>& broker, void* cookie) {
357 if (broker != nullptr) return broker->getStreamOutLatencyModeCallback(cookie);
358 return nullptr;
359}
360
361/*
362Note on the callback ownership.
363
364In the Binder ownership model, the server implementation is kept alive
365as long as there is any client (proxy object) alive. This is done by
366incrementing the refcount of the server-side object by the Binder framework.
367When it detects that the last client is gone, it decrements the refcount back.
368
369Thus, it is not needed to keep any references to StreamCallback on our
370side (after we have sent an instance to the client), because we are
371the server-side. The callback object will be kept alive as long as the HAL server
372holds a strong ref to IStreamCallback proxy.
373*/
374
375class OutputStreamCallbackAidl : public StreamCallbackBase,
376 public StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>,
377 public ::aidl::android::hardware::audio::core::BnStreamCallback {
378 public:
379 explicit OutputStreamCallbackAidl(const sp<CallbackBroker>& broker)
380 : StreamCallbackBase(broker),
381 StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>(
382 *static_cast<StreamCallbackBase*>(this)) {}
383 ndk::ScopedAStatus onTransferReady() override {
384 return runCb([](CbRef cb) { cb->onWriteReady(); });
385 }
386 ndk::ScopedAStatus onError() override {
387 return runCb([](CbRef cb) { cb->onError(); });
388 }
389 ndk::ScopedAStatus onDrainReady() override {
390 return runCb([](CbRef cb) { cb->onDrainReady(); });
391 }
392};
393
394class OutputStreamEventCallbackAidl :
395 public StreamCallbackBase,
396 public StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>,
397 public StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>,
398 public ::aidl::android::hardware::audio::core::BnStreamOutEventCallback {
399 public:
400 explicit OutputStreamEventCallbackAidl(const sp<CallbackBroker>& broker)
401 : StreamCallbackBase(broker),
402 StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>(
403 *static_cast<StreamCallbackBase*>(this)),
404 StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>(
405 *static_cast<StreamCallbackBase*>(this)) {}
406 ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& in_audioMetadata) override {
407 std::basic_string<uint8_t> halMetadata(in_audioMetadata.begin(), in_audioMetadata.end());
408 return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb(
409 [&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); });
410 }
411 ndk::ScopedAStatus onRecommendedLatencyModeChanged(
412 const std::vector<AudioLatencyMode>& in_modes) override {
413 auto halModes = VALUE_OR_FATAL(
414 ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
415 in_modes,
416 ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
417 return StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::runCb(
418 [&halModes](auto cb) { cb->onRecommendedLatencyModeChanged(halModes); });
419 }
420};
421
422} // namespace
423
Mikhail Naganov31d46652023-01-10 18:29:25 +0000424status_t DeviceHalAidl::openOutputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800425 audio_io_handle_t handle, audio_devices_t devices,
426 audio_output_flags_t flags, struct audio_config* config,
427 const char* address,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000428 sp<StreamOutHalInterface>* outStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800429 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000430 if (!outStream || !config) {
431 return BAD_VALUE;
432 }
433 TIME_CHECK();
434 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800435 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
436 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
437 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
438 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, false /*isInput*/));
439 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
440 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
441 int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
442 ::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
443 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
444 AudioPortConfig mixPortConfig;
445 Cleanups cleanups;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800446 int32_t nominalLatency;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800447 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
448 AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
449 config, &cleanups, &aidlConfig, &mixPortConfig, &nominalLatency));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800450 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
451 args.portConfigId = mixPortConfig.id;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800452 const bool isOffload = isBitPositionFlagSet(
453 aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD);
454 std::shared_ptr<OutputStreamCallbackAidl> streamCb;
455 if (isOffload) {
456 streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
457 }
458 auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
459 if (isOffload) {
460 args.offloadInfo = aidlConfig.offloadInfo;
461 args.callback = streamCb;
462 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800463 args.bufferSizeFrames = aidlConfig.frameCount;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800464 args.eventCallback = eventCb;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800465 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
466 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800467 StreamContextAidl context(ret.desc, isOffload);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800468 if (!context.isValid()) {
469 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
470 __func__, ret.desc.toString().c_str());
471 return NO_INIT;
472 }
473 *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), nominalLatency,
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800474 std::move(ret.stream), this /*callbackBroker*/);
475 void* cbCookie = (*outStream).get();
476 {
477 std::lock_guard l(mLock);
478 mCallbacks.emplace(cbCookie, Callbacks{});
479 }
480 if (streamCb) streamCb->setCookie(cbCookie);
481 eventCb->setCookie(cbCookie);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800482 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000483 return OK;
484}
485
Mikhail Naganov31d46652023-01-10 18:29:25 +0000486status_t DeviceHalAidl::openInputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800487 audio_io_handle_t handle, audio_devices_t devices,
488 struct audio_config* config, audio_input_flags_t flags,
489 const char* address, audio_source_t source,
490 audio_devices_t outputDevice, const char* outputDeviceAddress,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000491 sp<StreamInHalInterface>* inStream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800492 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000493 if (!inStream || !config) {
494 return BAD_VALUE;
495 }
496 TIME_CHECK();
497 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800498 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
499 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
500 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
501 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
502 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
503 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
504 int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
505 ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
506 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
507 AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
508 ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
509 AudioPortConfig mixPortConfig;
510 Cleanups cleanups;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800511 int32_t nominalLatency;
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800512 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, aidlSource,
513 config, &cleanups, &aidlConfig, &mixPortConfig, &nominalLatency));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800514 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
515 args.portConfigId = mixPortConfig.id;
516 RecordTrackMetadata aidlTrackMetadata{
517 .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
518 if (outputDevice != AUDIO_DEVICE_NONE) {
519 aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
520 ::aidl::android::legacy2aidl_audio_device_AudioDevice(
521 outputDevice, outputDeviceAddress));
522 }
523 args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
524 args.bufferSizeFrames = aidlConfig.frameCount;
525 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
526 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800527 StreamContextAidl context(ret.desc, false /*isAsynchronous*/);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800528 if (!context.isValid()) {
529 ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
530 __func__, ret.desc.toString().c_str());
531 return NO_INIT;
532 }
533 *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), nominalLatency,
534 std::move(ret.stream));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800535 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000536 return OK;
537}
538
539status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
540 *supportsPatches = true;
541 return OK;
542}
543
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800544status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
545 const struct audio_port_config* sources,
546 unsigned int num_sinks,
547 const struct audio_port_config* sinks,
548 audio_patch_handle_t* patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800549 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000550 TIME_CHECK();
551 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800552 if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
553 sources == nullptr || sinks == nullptr || patch == nullptr) {
554 return BAD_VALUE;
555 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800556 // When the patch handle (*patch) is AUDIO_PATCH_HANDLE_NONE, it means
557 // the framework wants to create a new patch. The handle has to be generated
558 // by the HAL. Since handles generated this way can only be unique within
559 // a HAL module, the framework generates a globally unique handle, and maps
560 // it on the <HAL module, patch handle> pair.
561 // When the patch handle is set, it meant the framework intends to update
562 // an existing patch.
563 //
564 // This behavior corresponds to HAL module behavior, with the only difference
565 // that the HAL module uses `int32_t` for patch IDs. The following assert ensures
566 // that both the framework and the HAL use the same value for "no ID":
567 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
568 int32_t halPatchId = static_cast<int32_t>(*patch);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800569
570 // Upon conversion, mix port configs contain audio configuration, while
571 // device port configs contain device address. This data is used to find
572 // or create HAL configs.
573 std::vector<AudioPortConfig> aidlSources, aidlSinks;
574 for (unsigned int i = 0; i < num_sources; ++i) {
575 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
576 sources[i].role, sources[i].type)) ==
577 ::aidl::android::AudioPortDirection::INPUT;
578 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
579 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
580 sources[i], isInput, 0)));
581 }
582 for (unsigned int i = 0; i < num_sinks; ++i) {
583 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
584 sinks[i].role, sinks[i].type)) ==
585 ::aidl::android::AudioPortDirection::INPUT;
586 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
587 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
588 sinks[i], isInput, 0)));
589 }
590 Cleanups cleanups;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800591 auto existingPatchIt = halPatchId != 0 ? mPatches.find(halPatchId): mPatches.end();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800592 AudioPatch aidlPatch;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800593 if (existingPatchIt != mPatches.end()) {
594 aidlPatch = existingPatchIt->second;
595 aidlPatch.sourcePortConfigIds.clear();
596 aidlPatch.sinkPortConfigIds.clear();
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800597 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800598 ALOGD("%s: sources: %s, sinks: %s",
599 __func__, ::android::internal::ToString(aidlSources).c_str(),
600 ::android::internal::ToString(aidlSinks).c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800601 auto fillPortConfigs = [&](
602 const std::vector<AudioPortConfig>& configs, std::vector<int32_t>* ids) -> status_t {
603 for (const auto& s : configs) {
604 AudioPortConfig portConfig;
605 bool created = false;
606 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(s, &portConfig, &created));
607 if (created) {
608 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, portConfig.id);
609 }
610 ids->push_back(portConfig.id);
611 }
612 return OK;
613 };
614 RETURN_STATUS_IF_ERROR(fillPortConfigs(aidlSources, &aidlPatch.sourcePortConfigIds));
615 RETURN_STATUS_IF_ERROR(fillPortConfigs(aidlSinks, &aidlPatch.sinkPortConfigIds));
616 if (existingPatchIt != mPatches.end()) {
617 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
618 mModule->setAudioPatch(aidlPatch, &aidlPatch)));
619 existingPatchIt->second = aidlPatch;
620 } else {
621 bool created = false;
622 RETURN_STATUS_IF_ERROR(findOrCreatePatch(aidlPatch, &aidlPatch, &created));
623 // Since no cleanup of the patch is needed, 'created' is ignored.
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800624 halPatchId = aidlPatch.id;
625 *patch = static_cast<audio_patch_handle_t>(halPatchId);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800626 }
627 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000628 return OK;
629}
630
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800631status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800632 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000633 TIME_CHECK();
634 if (!mModule) return NO_INIT;
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800635 static_assert(AUDIO_PATCH_HANDLE_NONE == 0);
636 if (patch == AUDIO_PATCH_HANDLE_NONE) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800637 return BAD_VALUE;
638 }
Mikhail Naganov47d1d732023-02-23 15:16:04 -0800639 int32_t halPatchId = static_cast<int32_t>(patch);
640 auto patchIt = mPatches.find(halPatchId);
641 if (patchIt == mPatches.end()) {
642 ALOGE("%s: patch with id %d not found", __func__, halPatchId);
643 return BAD_VALUE;
644 }
645 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->resetAudioPatch(halPatchId)));
646 mPatches.erase(patchIt);
Shunkai Yao51202502022-12-12 06:11:46 +0000647 return OK;
648}
649
Mikhail Naganov31d46652023-01-10 18:29:25 +0000650status_t DeviceHalAidl::getAudioPort(struct audio_port* port __unused) {
651 TIME_CHECK();
652 ALOGE("%s not implemented yet", __func__);
653 return INVALID_OPERATION;
654}
655
656status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port __unused) {
657 TIME_CHECK();
658 ALOGE("%s not implemented yet", __func__);
659 return INVALID_OPERATION;
660}
661
662status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config __unused) {
663 TIME_CHECK();
664 if (!mModule) return NO_INIT;
665 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000666 return OK;
667}
668
669status_t DeviceHalAidl::getMicrophones(
Mikhail Naganov31d46652023-01-10 18:29:25 +0000670 std::vector<audio_microphone_characteristic_t>* microphones __unused) {
671 TIME_CHECK();
672 if (!mModule) return NO_INIT;
673 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000674 return OK;
675}
676
Mikhail Naganov31d46652023-01-10 18:29:25 +0000677status_t DeviceHalAidl::addDeviceEffect(audio_port_handle_t device __unused,
678 sp<EffectHalInterface> effect) {
Shunkai Yao51202502022-12-12 06:11:46 +0000679 if (!effect) {
680 return BAD_VALUE;
681 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000682 TIME_CHECK();
683 if (!mModule) return NO_INIT;
684 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000685 return OK;
686}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000687status_t DeviceHalAidl::removeDeviceEffect(audio_port_handle_t device __unused,
Shunkai Yao51202502022-12-12 06:11:46 +0000688 sp<EffectHalInterface> effect) {
689 if (!effect) {
690 return BAD_VALUE;
691 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000692 TIME_CHECK();
693 if (!mModule) return NO_INIT;
694 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000695 return OK;
696}
697
698status_t DeviceHalAidl::getMmapPolicyInfos(
699 media::audio::common::AudioMMapPolicyType policyType __unused,
700 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos __unused) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000701 TIME_CHECK();
Shunkai Yao51202502022-12-12 06:11:46 +0000702 ALOGE("%s not implemented yet", __func__);
703 return OK;
704}
705
706int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000707 TIME_CHECK();
Shunkai Yao51202502022-12-12 06:11:46 +0000708 ALOGE("%s not implemented yet", __func__);
709 return OK;
710}
711
712int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000713 TIME_CHECK();
Shunkai Yao51202502022-12-12 06:11:46 +0000714 ALOGE("%s not implemented yet", __func__);
715 return OK;
716}
717
718error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000719 TIME_CHECK();
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700720 if (!mModule) return NO_INIT;
721 int32_t aidlHwAvSync;
722 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->generateHwAvSyncId(&aidlHwAvSync)));
723 return VALUE_OR_RETURN_STATUS(
724 ::aidl::android::aidl2legacy_int32_t_audio_hw_sync_t(aidlHwAvSync));
Shunkai Yao51202502022-12-12 06:11:46 +0000725}
726
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000727status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
728 TIME_CHECK();
729 if (!mModule) return NO_INIT;
730 return mModule->dump(fd, Args(args).args(), args.size());
Shunkai Yao51202502022-12-12 06:11:46 +0000731};
732
Mikhail Naganov31d46652023-01-10 18:29:25 +0000733int32_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports __unused) {
734 TIME_CHECK();
Shunkai Yao51202502022-12-12 06:11:46 +0000735 ALOGE("%s not implemented yet", __func__);
736 return INVALID_OPERATION;
737}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000738
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800739bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
740 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
741 return p.ext.get<AudioPortExt::Tag::device>().device == device;
742}
743
744bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
745 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
746 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
747 return p.portId == mDefaultInputPortId;
748 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
749 return p.portId == mDefaultOutputPortId;
750 }
751 return p.ext.get<AudioPortExt::Tag::device>().device == device;
752}
753
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800754status_t DeviceHalAidl::createPortConfig(
755 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800756 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800757 AudioPortConfig appliedPortConfig;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800758 bool applied = false;
759 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800760 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800761 if (!applied) {
762 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800763 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800764 if (!applied) {
765 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800766 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800767 return NO_INIT;
768 }
769 }
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800770 auto id = appliedPortConfig.id;
771 auto [it, inserted] = mPortConfigs.emplace(std::move(id), std::move(appliedPortConfig));
772 LOG_ALWAYS_FATAL_IF(!inserted, "%s: port config with id %d already exists",
773 __func__, it->first);
774 *result = it;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800775 return OK;
776}
777
778status_t DeviceHalAidl::findOrCreatePatch(
779 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
780 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
781 requestedPatch.sourcePortConfigIds.end());
782 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
783 requestedPatch.sinkPortConfigIds.end());
784 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
785}
786
787status_t DeviceHalAidl::findOrCreatePatch(
788 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
789 AudioPatch* patch, bool* created) {
790 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
791 if (patchIt == mPatches.end()) {
792 TIME_CHECK();
793 AudioPatch requestedPatch, appliedPatch;
794 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
795 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
796 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
797 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
798 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
799 requestedPatch, &appliedPatch)));
800 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
801 *created = true;
802 } else {
803 *created = false;
804 }
805 *patch = patchIt->second;
806 return OK;
807}
808
809status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device,
810 AudioPortConfig* portConfig, bool* created) {
811 auto portConfigIt = findPortConfig(device);
812 if (portConfigIt == mPortConfigs.end()) {
813 auto portsIt = findPort(device);
814 if (portsIt == mPorts.end()) {
815 ALOGE("%s: device port for device %s is not found in the module %s",
816 __func__, device.toString().c_str(), mInstance.c_str());
817 return BAD_VALUE;
818 }
819 AudioPortConfig requestedPortConfig;
820 requestedPortConfig.portId = portsIt->first;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800821 RETURN_STATUS_IF_ERROR(createPortConfig(requestedPortConfig, &portConfigIt));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800822 *created = true;
823 } else {
824 *created = false;
825 }
826 *portConfig = portConfigIt->second;
827 return OK;
828}
829
830status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800831 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800832 AudioSource source, AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800833 // These flags get removed one by one in this order when retrying port finding.
834 static const std::vector<AudioInputFlags> kOptionalInputFlags{
835 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800836 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800837 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800838 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
839 AudioIoFlags matchFlags = flags.value();
840 auto portsIt = findPort(config, matchFlags);
841 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
842 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
843 if (!isBitPositionFlagSet(
844 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
845 ++optionalInputFlagsIt;
846 continue;
847 }
848 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
849 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
850 portsIt = findPort(config, matchFlags);
851 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
852 "retried with flags %s", __func__, config.toString().c_str(),
853 flags.value().toString().c_str(), mInstance.c_str(),
854 matchFlags.toString().c_str());
855 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800856 if (portsIt == mPorts.end()) {
857 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800858 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800859 mInstance.c_str());
860 return BAD_VALUE;
861 }
862 AudioPortConfig requestedPortConfig;
863 requestedPortConfig.portId = portsIt->first;
864 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800865 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800866 if (matchFlags.getTag() == AudioIoFlags::Tag::input
867 && source != AudioSource::SYS_RESERVED_INVALID) {
868 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
869 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
870 }
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800871 RETURN_STATUS_IF_ERROR(createPortConfig(requestedPortConfig, &portConfigIt));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800872 *created = true;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800873 } else if (!flags.has_value()) {
874 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
875 "and was not created as flags are not specified",
876 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
877 return BAD_VALUE;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800878 } else {
879 *created = false;
880 }
881 *portConfig = portConfigIt->second;
882 return OK;
883}
884
885status_t DeviceHalAidl::findOrCreatePortConfig(
886 const AudioPortConfig& requestedPortConfig, AudioPortConfig* portConfig, bool* created) {
887 using Tag = AudioPortExt::Tag;
888 if (requestedPortConfig.ext.getTag() == Tag::mix) {
889 if (const auto& p = requestedPortConfig;
890 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800891 !p.format.has_value()) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800892 ALOGW("%s: provided mix port config is not fully specified: %s",
893 __func__, p.toString().c_str());
894 return BAD_VALUE;
895 }
896 AudioConfig config;
897 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800898 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
899 AudioPortMixExtUseCase::Tag::source ?
900 requestedPortConfig.ext.get<Tag::mix>().usecase.
901 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800902 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800903 requestedPortConfig.ext.get<Tag::mix>().handle, source, portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800904 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
905 return findOrCreatePortConfig(
906 requestedPortConfig.ext.get<Tag::device>().device, portConfig, created);
907 }
908 ALOGW("%s: unsupported audio port config: %s",
909 __func__, requestedPortConfig.toString().c_str());
910 return BAD_VALUE;
911}
912
913DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
914 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
915 return std::find_if(mPatches.begin(), mPatches.end(),
916 [&](const auto& pair) {
917 const auto& p = pair.second;
918 std::set<int32_t> patchSrcs(
919 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
920 std::set<int32_t> patchSinks(
921 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
922 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
923}
924
925DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800926 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
927 return mPorts.find(mDefaultInputPortId);
928 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
929 return mPorts.find(mDefaultOutputPortId);
930 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800931 return std::find_if(mPorts.begin(), mPorts.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800932 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800933}
934
935DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
936 const AudioConfig& config, const AudioIoFlags& flags) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800937 auto matcher = [&](const auto& pair) {
938 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800939 return p.ext.getTag() == AudioPortExt::Tag::mix &&
940 p.flags == flags &&
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800941 std::find_if(p.profiles.begin(), p.profiles.end(),
942 [&](const auto& prof) {
943 return prof.format == config.base.format &&
944 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
945 config.base.channelMask) != prof.channelMasks.end() &&
946 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
947 config.base.sampleRate) != prof.sampleRates.end();
948 }) != p.profiles.end(); };
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800949 return std::find_if(mPorts.begin(), mPorts.end(), matcher);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800950}
951
952DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800953 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800954 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800955}
956
957DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800958 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800959 using Tag = AudioPortExt::Tag;
960 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
961 [&](const auto& pair) {
962 const auto& p = pair.second;
963 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
964 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
965 !p.format.has_value() || !p.flags.has_value(),
966 "%s: stored mix port config is not fully specified: %s",
967 __func__, p.toString().c_str());
968 return p.ext.getTag() == Tag::mix &&
969 isConfigEqualToPortConfig(config, p) &&
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800970 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800971 p.ext.template get<Tag::mix>().handle == ioHandle; });
972}
973/*
974DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
975 const AudioPortConfig& portConfig) {
976 using Tag = AudioPortExt::Tag;
977 if (portConfig.ext.getTag() == Tag::mix) {
978 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
979 [&](const auto& pair) {
980 const auto& p = pair.second;
981 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
982 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
983 !p.format.has_value() || !p.flags.has_value(),
984 "%s: stored mix port config is not fully specified: %s",
985 __func__, p.toString().c_str());
986 return p.ext.getTag() == Tag::mix &&
987 (!portConfig.sampleRate.has_value() ||
988 p.sampleRate == portConfig.sampleRate) &&
989 (!portConfig.channelMask.has_value() ||
990 p.channelMask == portConfig.channelMask) &&
991 (!portConfig.format.has_value() || p.format == portConfig.format) &&
992 (!portConfig.flags.has_value() || p.flags == portConfig.flags) &&
993 p.ext.template get<Tag::mix>().handle ==
994 portConfig.ext.template get<Tag::mix>().handle; });
995 } else if (portConfig.ext.getTag() == Tag::device) {
996 return findPortConfig(portConfig.ext.get<Tag::device>().device);
997 }
998 return mPortConfigs.end();
999}
1000*/
1001void DeviceHalAidl::resetPatch(int32_t patchId) {
1002 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1003 mPatches.erase(it);
1004 TIME_CHECK();
1005 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1006 ALOGE("%s: error while resetting patch %d: %s",
1007 __func__, patchId, status.getDescription().c_str());
1008 }
1009 return;
1010 }
1011 ALOGE("%s: patch id %d not found", __func__, patchId);
1012}
1013
1014void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1015 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1016 mPortConfigs.erase(it);
1017 TIME_CHECK();
1018 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1019 !status.isOk()) {
1020 ALOGE("%s: error while resetting port config %d: %s",
1021 __func__, portConfigId, status.getDescription().c_str());
1022 }
1023 return;
1024 }
1025 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1026}
1027
Mikhail Naganovdfd594e2023-02-08 16:59:41 -08001028void DeviceHalAidl::clearCallbacks(void* cookie) {
1029 std::lock_guard l(mLock);
1030 mCallbacks.erase(cookie);
1031}
1032
1033sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1034 return getCallbackImpl(cookie, &Callbacks::out);
1035}
1036
1037void DeviceHalAidl::setStreamOutCallback(
1038 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1039 setCallbackImpl(cookie, &Callbacks::out, cb);
1040}
1041
1042sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1043 void* cookie) {
1044 return getCallbackImpl(cookie, &Callbacks::event);
1045}
1046
1047void DeviceHalAidl::setStreamOutEventCallback(
1048 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1049 setCallbackImpl(cookie, &Callbacks::event, cb);
1050}
1051
1052sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1053 void* cookie) {
1054 return getCallbackImpl(cookie, &Callbacks::latency);
1055}
1056
1057void DeviceHalAidl::setStreamOutLatencyModeCallback(
1058 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1059 setCallbackImpl(cookie, &Callbacks::latency, cb);
1060}
1061
1062template<class C>
1063sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1064 std::lock_guard l(mLock);
1065 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1066 return ((it->second).*field).promote();
1067 }
1068 return nullptr;
1069}
1070template<class C>
1071void DeviceHalAidl::setCallbackImpl(
1072 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1073 std::lock_guard l(mLock);
1074 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1075 (it->second).*field = cb;
1076 }
1077}
1078
Mikhail Naganov31d46652023-01-10 18:29:25 +00001079} // namespace android