blob: 4d1a18bfc9af7065f3970317cfe605e0b5e6e726 [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 Naganov5b1eed12023-01-25 11:29:11 -080054using aidl::android::hardware::audio::common::RecordTrackMetadata;
55using aidl::android::hardware::audio::core::AudioPatch;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000056using aidl::android::hardware::audio::core::IModule;
57using aidl::android::hardware::audio::core::ITelephony;
58using aidl::android::hardware::audio::core::StreamDescriptor;
Mikhail Naganov89a9f742023-01-30 12:33:18 -080059using android::hardware::audio::common::getFrameSizeInBytes;
60using android::hardware::audio::common::isBitPositionFlagSet;
61using android::hardware::audio::common::makeBitPositionFlagMask;
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();
Shunkai Yao51202502022-12-12 06:11:46 +0000720 ALOGE("%s not implemented yet", __func__);
721 return base::unexpected(INVALID_OPERATION);
722}
723
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000724status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
725 TIME_CHECK();
726 if (!mModule) return NO_INIT;
727 return mModule->dump(fd, Args(args).args(), args.size());
Shunkai Yao51202502022-12-12 06:11:46 +0000728};
729
Mikhail Naganov31d46652023-01-10 18:29:25 +0000730int32_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports __unused) {
731 TIME_CHECK();
Shunkai Yao51202502022-12-12 06:11:46 +0000732 ALOGE("%s not implemented yet", __func__);
733 return INVALID_OPERATION;
734}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000735
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800736bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
737 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
738 return p.ext.get<AudioPortExt::Tag::device>().device == device;
739}
740
741bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
742 if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
743 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
744 return p.portId == mDefaultInputPortId;
745 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
746 return p.portId == mDefaultOutputPortId;
747 }
748 return p.ext.get<AudioPortExt::Tag::device>().device == device;
749}
750
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800751status_t DeviceHalAidl::createPortConfig(
752 const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800753 TIME_CHECK();
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800754 AudioPortConfig appliedPortConfig;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800755 bool applied = false;
756 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800757 requestedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800758 if (!applied) {
759 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800760 appliedPortConfig, &appliedPortConfig, &applied)));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800761 if (!applied) {
762 ALOGE("%s: module %s did not apply suggested config %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800763 __func__, mInstance.c_str(), appliedPortConfig.toString().c_str());
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800764 return NO_INIT;
765 }
766 }
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800767 auto id = appliedPortConfig.id;
768 auto [it, inserted] = mPortConfigs.emplace(std::move(id), std::move(appliedPortConfig));
769 LOG_ALWAYS_FATAL_IF(!inserted, "%s: port config with id %d already exists",
770 __func__, it->first);
771 *result = it;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800772 return OK;
773}
774
775status_t DeviceHalAidl::findOrCreatePatch(
776 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
777 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
778 requestedPatch.sourcePortConfigIds.end());
779 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
780 requestedPatch.sinkPortConfigIds.end());
781 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
782}
783
784status_t DeviceHalAidl::findOrCreatePatch(
785 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
786 AudioPatch* patch, bool* created) {
787 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
788 if (patchIt == mPatches.end()) {
789 TIME_CHECK();
790 AudioPatch requestedPatch, appliedPatch;
791 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
792 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
793 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
794 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
795 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
796 requestedPatch, &appliedPatch)));
797 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
798 *created = true;
799 } else {
800 *created = false;
801 }
802 *patch = patchIt->second;
803 return OK;
804}
805
806status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device,
807 AudioPortConfig* portConfig, bool* created) {
808 auto portConfigIt = findPortConfig(device);
809 if (portConfigIt == mPortConfigs.end()) {
810 auto portsIt = findPort(device);
811 if (portsIt == mPorts.end()) {
812 ALOGE("%s: device port for device %s is not found in the module %s",
813 __func__, device.toString().c_str(), mInstance.c_str());
814 return BAD_VALUE;
815 }
816 AudioPortConfig requestedPortConfig;
817 requestedPortConfig.portId = portsIt->first;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800818 RETURN_STATUS_IF_ERROR(createPortConfig(requestedPortConfig, &portConfigIt));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800819 *created = true;
820 } else {
821 *created = false;
822 }
823 *portConfig = portConfigIt->second;
824 return OK;
825}
826
827status_t DeviceHalAidl::findOrCreatePortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800828 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800829 AudioSource source, AudioPortConfig* portConfig, bool* created) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800830 // These flags get removed one by one in this order when retrying port finding.
831 static const std::vector<AudioInputFlags> kOptionalInputFlags{
832 AudioInputFlags::FAST, AudioInputFlags::RAW };
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800833 auto portConfigIt = findPortConfig(config, flags, ioHandle);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800834 if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800835 auto optionalInputFlagsIt = kOptionalInputFlags.begin();
836 AudioIoFlags matchFlags = flags.value();
837 auto portsIt = findPort(config, matchFlags);
838 while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
839 && optionalInputFlagsIt != kOptionalInputFlags.end()) {
840 if (!isBitPositionFlagSet(
841 matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
842 ++optionalInputFlagsIt;
843 continue;
844 }
845 matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
846 ~makeBitPositionFlagMask(*optionalInputFlagsIt++));
847 portsIt = findPort(config, matchFlags);
848 ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
849 "retried with flags %s", __func__, config.toString().c_str(),
850 flags.value().toString().c_str(), mInstance.c_str(),
851 matchFlags.toString().c_str());
852 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800853 if (portsIt == mPorts.end()) {
854 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800855 __func__, config.toString().c_str(), matchFlags.toString().c_str(),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800856 mInstance.c_str());
857 return BAD_VALUE;
858 }
859 AudioPortConfig requestedPortConfig;
860 requestedPortConfig.portId = portsIt->first;
861 setPortConfigFromConfig(&requestedPortConfig, config);
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800862 requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800863 if (matchFlags.getTag() == AudioIoFlags::Tag::input
864 && source != AudioSource::SYS_RESERVED_INVALID) {
865 requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
866 AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
867 }
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800868 RETURN_STATUS_IF_ERROR(createPortConfig(requestedPortConfig, &portConfigIt));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800869 *created = true;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800870 } else if (!flags.has_value()) {
871 ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
872 "and was not created as flags are not specified",
873 __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
874 return BAD_VALUE;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800875 } else {
876 *created = false;
877 }
878 *portConfig = portConfigIt->second;
879 return OK;
880}
881
882status_t DeviceHalAidl::findOrCreatePortConfig(
883 const AudioPortConfig& requestedPortConfig, AudioPortConfig* portConfig, bool* created) {
884 using Tag = AudioPortExt::Tag;
885 if (requestedPortConfig.ext.getTag() == Tag::mix) {
886 if (const auto& p = requestedPortConfig;
887 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800888 !p.format.has_value()) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800889 ALOGW("%s: provided mix port config is not fully specified: %s",
890 __func__, p.toString().c_str());
891 return BAD_VALUE;
892 }
893 AudioConfig config;
894 setConfigFromPortConfig(&config, requestedPortConfig);
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800895 AudioSource source = requestedPortConfig.ext.get<Tag::mix>().usecase.getTag() ==
896 AudioPortMixExtUseCase::Tag::source ?
897 requestedPortConfig.ext.get<Tag::mix>().usecase.
898 get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800899 return findOrCreatePortConfig(config, requestedPortConfig.flags,
Mikhail Naganovd8d01f72023-03-09 16:24:40 -0800900 requestedPortConfig.ext.get<Tag::mix>().handle, source, portConfig, created);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800901 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
902 return findOrCreatePortConfig(
903 requestedPortConfig.ext.get<Tag::device>().device, portConfig, created);
904 }
905 ALOGW("%s: unsupported audio port config: %s",
906 __func__, requestedPortConfig.toString().c_str());
907 return BAD_VALUE;
908}
909
910DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
911 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
912 return std::find_if(mPatches.begin(), mPatches.end(),
913 [&](const auto& pair) {
914 const auto& p = pair.second;
915 std::set<int32_t> patchSrcs(
916 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
917 std::set<int32_t> patchSinks(
918 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
919 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
920}
921
922DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800923 if (device.type.type == AudioDeviceType::IN_DEFAULT) {
924 return mPorts.find(mDefaultInputPortId);
925 } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
926 return mPorts.find(mDefaultOutputPortId);
927 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800928 return std::find_if(mPorts.begin(), mPorts.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800929 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800930}
931
932DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
933 const AudioConfig& config, const AudioIoFlags& flags) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800934 auto matcher = [&](const auto& pair) {
935 const auto& p = pair.second;
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800936 return p.ext.getTag() == AudioPortExt::Tag::mix &&
937 p.flags == flags &&
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800938 std::find_if(p.profiles.begin(), p.profiles.end(),
939 [&](const auto& prof) {
940 return prof.format == config.base.format &&
941 std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
942 config.base.channelMask) != prof.channelMasks.end() &&
943 std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
944 config.base.sampleRate) != prof.sampleRates.end();
945 }) != p.profiles.end(); };
Mikhail Naganov1a44bc62023-02-16 17:35:06 -0800946 return std::find_if(mPorts.begin(), mPorts.end(), matcher);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800947}
948
949DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800950 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800951 [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800952}
953
954DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800955 const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800956 using Tag = AudioPortExt::Tag;
957 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
958 [&](const auto& pair) {
959 const auto& p = pair.second;
960 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
961 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
962 !p.format.has_value() || !p.flags.has_value(),
963 "%s: stored mix port config is not fully specified: %s",
964 __func__, p.toString().c_str());
965 return p.ext.getTag() == Tag::mix &&
966 isConfigEqualToPortConfig(config, p) &&
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800967 (!flags.has_value() || p.flags.value() == flags.value()) &&
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800968 p.ext.template get<Tag::mix>().handle == ioHandle; });
969}
970/*
971DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
972 const AudioPortConfig& portConfig) {
973 using Tag = AudioPortExt::Tag;
974 if (portConfig.ext.getTag() == Tag::mix) {
975 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
976 [&](const auto& pair) {
977 const auto& p = pair.second;
978 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
979 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
980 !p.format.has_value() || !p.flags.has_value(),
981 "%s: stored mix port config is not fully specified: %s",
982 __func__, p.toString().c_str());
983 return p.ext.getTag() == Tag::mix &&
984 (!portConfig.sampleRate.has_value() ||
985 p.sampleRate == portConfig.sampleRate) &&
986 (!portConfig.channelMask.has_value() ||
987 p.channelMask == portConfig.channelMask) &&
988 (!portConfig.format.has_value() || p.format == portConfig.format) &&
989 (!portConfig.flags.has_value() || p.flags == portConfig.flags) &&
990 p.ext.template get<Tag::mix>().handle ==
991 portConfig.ext.template get<Tag::mix>().handle; });
992 } else if (portConfig.ext.getTag() == Tag::device) {
993 return findPortConfig(portConfig.ext.get<Tag::device>().device);
994 }
995 return mPortConfigs.end();
996}
997*/
998void DeviceHalAidl::resetPatch(int32_t patchId) {
999 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
1000 mPatches.erase(it);
1001 TIME_CHECK();
1002 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
1003 ALOGE("%s: error while resetting patch %d: %s",
1004 __func__, patchId, status.getDescription().c_str());
1005 }
1006 return;
1007 }
1008 ALOGE("%s: patch id %d not found", __func__, patchId);
1009}
1010
1011void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
1012 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
1013 mPortConfigs.erase(it);
1014 TIME_CHECK();
1015 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
1016 !status.isOk()) {
1017 ALOGE("%s: error while resetting port config %d: %s",
1018 __func__, portConfigId, status.getDescription().c_str());
1019 }
1020 return;
1021 }
1022 ALOGE("%s: port config id %d not found", __func__, portConfigId);
1023}
1024
Mikhail Naganovdfd594e2023-02-08 16:59:41 -08001025void DeviceHalAidl::clearCallbacks(void* cookie) {
1026 std::lock_guard l(mLock);
1027 mCallbacks.erase(cookie);
1028}
1029
1030sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) {
1031 return getCallbackImpl(cookie, &Callbacks::out);
1032}
1033
1034void DeviceHalAidl::setStreamOutCallback(
1035 void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) {
1036 setCallbackImpl(cookie, &Callbacks::out, cb);
1037}
1038
1039sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback(
1040 void* cookie) {
1041 return getCallbackImpl(cookie, &Callbacks::event);
1042}
1043
1044void DeviceHalAidl::setStreamOutEventCallback(
1045 void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) {
1046 setCallbackImpl(cookie, &Callbacks::event, cb);
1047}
1048
1049sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback(
1050 void* cookie) {
1051 return getCallbackImpl(cookie, &Callbacks::latency);
1052}
1053
1054void DeviceHalAidl::setStreamOutLatencyModeCallback(
1055 void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) {
1056 setCallbackImpl(cookie, &Callbacks::latency, cb);
1057}
1058
1059template<class C>
1060sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) {
1061 std::lock_guard l(mLock);
1062 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1063 return ((it->second).*field).promote();
1064 }
1065 return nullptr;
1066}
1067template<class C>
1068void DeviceHalAidl::setCallbackImpl(
1069 void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) {
1070 std::lock_guard l(mLock);
1071 if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) {
1072 (it->second).*field = cb;
1073 }
1074}
1075
Mikhail Naganov31d46652023-01-10 18:29:25 +00001076} // namespace android