blob: a7537c164d1dce2fff2e09dee2ef6d819e344cf5 [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"
18
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080019#include <algorithm>
20#include <forward_list>
21
Mikhail Naganovfab697c2023-01-11 19:33:13 +000022#include <aidl/android/hardware/audio/core/StreamDescriptor.h>
23#include <error/expected_utils.h>
24#include <media/AidlConversionCppNdk.h>
25#include <media/AidlConversionUtil.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000026#include <mediautils/TimeCheck.h>
27#include <utils/Log.h>
Shunkai Yao51202502022-12-12 06:11:46 +000028
Mikhail Naganov31d46652023-01-10 18:29:25 +000029#include "DeviceHalAidl.h"
30#include "StreamHalAidl.h"
31
Mikhail Naganovfab697c2023-01-11 19:33:13 +000032using aidl::android::aidl_utils::statusTFromBinderStatus;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080033using aidl::android::media::audio::common::AudioConfig;
34using aidl::android::media::audio::common::AudioDevice;
35using aidl::android::media::audio::common::AudioIoFlags;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000036using aidl::android::media::audio::common::AudioMode;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080037using aidl::android::media::audio::common::AudioOutputFlags;
38using aidl::android::media::audio::common::AudioPort;
39using aidl::android::media::audio::common::AudioPortConfig;
40using aidl::android::media::audio::common::AudioPortExt;
41using aidl::android::media::audio::common::AudioSource;
42using aidl::android::media::audio::common::Int;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000043using aidl::android::media::audio::common::Float;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080044using aidl::android::hardware::audio::common::RecordTrackMetadata;
45using aidl::android::hardware::audio::core::AudioPatch;
Mikhail Naganovfab697c2023-01-11 19:33:13 +000046using aidl::android::hardware::audio::core::IModule;
47using aidl::android::hardware::audio::core::ITelephony;
48using aidl::android::hardware::audio::core::StreamDescriptor;
Mikhail Naganov31d46652023-01-10 18:29:25 +000049
50namespace android {
51
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080052namespace {
53
54bool isConfigEqualToPortConfig(const AudioConfig& config, const AudioPortConfig& portConfig) {
55 return portConfig.sampleRate.value().value == config.base.sampleRate &&
56 portConfig.channelMask.value() == config.base.channelMask &&
57 portConfig.format.value() == config.base.format;
58}
59
60void setConfigFromPortConfig(AudioConfig* config, const AudioPortConfig& portConfig) {
61 config->base.sampleRate = portConfig.sampleRate.value().value;
62 config->base.channelMask = portConfig.channelMask.value();
63 config->base.format = portConfig.format.value();
64}
65
66void setPortConfigFromConfig(AudioPortConfig* portConfig, const AudioConfig& config) {
67 portConfig->sampleRate = Int{ .value = config.base.sampleRate };
68 portConfig->channelMask = config.base.channelMask;
69 portConfig->format = config.base.format;
70}
71
72} // namespace
73
Mikhail Naganov31d46652023-01-10 18:29:25 +000074status_t DeviceHalAidl::getSupportedDevices(uint32_t*) {
75 // Obsolete.
76 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +000077}
78
79status_t DeviceHalAidl::initCheck() {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080080 TIME_CHECK();
Mikhail Naganov31d46652023-01-10 18:29:25 +000081 if (mModule == nullptr) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080082 std::vector<AudioPort> ports;
83 RETURN_STATUS_IF_ERROR(
84 statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
85 ALOGW_IF(ports.empty(), "%s: module %s returned an empty list of audio ports",
86 __func__, mInstance.c_str());
87 std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()),
88 [](const auto& p) { return std::make_pair(p.id, p); });
89 std::vector<AudioPortConfig> portConfigs;
90 RETURN_STATUS_IF_ERROR(
91 statusTFromBinderStatus(mModule->getAudioPortConfigs(&portConfigs))); // OK if empty
92 std::transform(portConfigs.begin(), portConfigs.end(),
93 std::inserter(mPortConfigs, mPortConfigs.end()),
94 [](const auto& p) { return std::make_pair(p.id, p); });
95 std::vector<AudioPatch> patches;
96 RETURN_STATUS_IF_ERROR(
97 statusTFromBinderStatus(mModule->getAudioPatches(&patches))); // OK if empty
98 std::transform(patches.begin(), patches.end(),
99 std::inserter(mPatches, mPatches.end()),
100 [](const auto& p) { return std::make_pair(p.id, p); });
Shunkai Yao51202502022-12-12 06:11:46 +0000101 return OK;
102}
103
104status_t DeviceHalAidl::setVoiceVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000105 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000106 if (!mModule) return NO_INIT;
107 std::shared_ptr<ITelephony> telephony;
108 if (ndk::ScopedAStatus status = mModule->getTelephony(&telephony);
109 status.isOk() && telephony != nullptr) {
110 ITelephony::TelecomConfig inConfig{ .voiceVolume = Float{volume} }, outConfig;
111 RETURN_STATUS_IF_ERROR(
112 statusTFromBinderStatus(telephony->setTelecomConfig(inConfig, &outConfig)));
113 ALOGW_IF(outConfig.voiceVolume.has_value() && volume != outConfig.voiceVolume.value().value,
114 "%s: the resulting voice volume %f is not the same as requested %f",
115 __func__, outConfig.voiceVolume.value().value, volume);
116 }
117 return INVALID_OPERATION;
Shunkai Yao51202502022-12-12 06:11:46 +0000118}
119
120status_t DeviceHalAidl::setMasterVolume(float volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000121 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000122 if (!mModule) return NO_INIT;
123 return statusTFromBinderStatus(mModule->setMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000124}
125
126status_t DeviceHalAidl::getMasterVolume(float *volume) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000127 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000128 if (!mModule) return NO_INIT;
129 return statusTFromBinderStatus(mModule->getMasterVolume(volume));
Shunkai Yao51202502022-12-12 06:11:46 +0000130}
131
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000132status_t DeviceHalAidl::setMode(audio_mode_t mode) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000133 TIME_CHECK();
134 if (!mModule) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000135 AudioMode audioMode = VALUE_OR_FATAL(::aidl::android::legacy2aidl_audio_mode_t_AudioMode(mode));
136 std::shared_ptr<ITelephony> telephony;
137 if (ndk::ScopedAStatus status = mModule->getTelephony(&telephony);
138 status.isOk() && telephony != nullptr) {
139 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(telephony->switchAudioMode(audioMode)));
140 }
141 return statusTFromBinderStatus(mModule->updateAudioMode(audioMode));
Shunkai Yao51202502022-12-12 06:11:46 +0000142}
143
144status_t DeviceHalAidl::setMicMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000145 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000146 if (!mModule) return NO_INIT;
147 return statusTFromBinderStatus(mModule->setMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000148}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000149
Shunkai Yao51202502022-12-12 06:11:46 +0000150status_t DeviceHalAidl::getMicMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000151 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000152 if (!mModule) return NO_INIT;
153 return statusTFromBinderStatus(mModule->getMicMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000154}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000155
Shunkai Yao51202502022-12-12 06:11:46 +0000156status_t DeviceHalAidl::setMasterMute(bool state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000157 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000158 if (!mModule) return NO_INIT;
159 return statusTFromBinderStatus(mModule->setMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000160}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000161
Shunkai Yao51202502022-12-12 06:11:46 +0000162status_t DeviceHalAidl::getMasterMute(bool *state) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000163 TIME_CHECK();
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000164 if (!mModule) return NO_INIT;
165 return statusTFromBinderStatus(mModule->getMasterMute(state));
Shunkai Yao51202502022-12-12 06:11:46 +0000166}
167
Mikhail Naganov31d46652023-01-10 18:29:25 +0000168status_t DeviceHalAidl::setParameters(const String8& kvPairs __unused) {
169 TIME_CHECK();
170 if (!mModule) return NO_INIT;
171 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000172 return OK;
173}
174
Mikhail Naganov31d46652023-01-10 18:29:25 +0000175status_t DeviceHalAidl::getParameters(const String8& keys __unused, String8 *values) {
176 TIME_CHECK();
177 values->clear();
178 if (!mModule) return NO_INIT;
179 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000180 return OK;
181}
182
Mikhail Naganov31d46652023-01-10 18:29:25 +0000183status_t DeviceHalAidl::getInputBufferSize(
184 const struct audio_config* config __unused, size_t* size __unused) {
185 TIME_CHECK();
186 if (!mModule) return NO_INIT;
187 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000188 return OK;
189}
190
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800191namespace {
192
193class Cleanup {
194 public:
195 typedef void (DeviceHalAidl::*Cleaner)(int32_t);
196
197 Cleanup(DeviceHalAidl* device, Cleaner cleaner, int32_t id) :
198 mDevice(device), mCleaner(cleaner), mId(id) {}
199 ~Cleanup() { clean(); }
200 void clean() {
201 if (mDevice != nullptr) (mDevice->*mCleaner)(mId);
202 disarm();
203 }
204 void disarm() { mDevice = nullptr; }
205
206 private:
207 DeviceHalAidl* mDevice;
208 const Cleaner mCleaner;
209 const int32_t mId;
210};
211
212} // namespace
213
214// Since the order of container elements destruction is unspecified,
215// ensure that cleanups are performed from the most recent one and upwards.
216// This is the same as if there were individual Cleanup instances on the stack,
217// however the bonus is that we can disarm all of them with just one statement.
218class DeviceHalAidl::Cleanups : public std::forward_list<Cleanup> {
219 public:
220 ~Cleanups() { for (auto& c : *this) c.clean(); }
221 void disarmAll() { for (auto& c : *this) c.disarm(); }
222};
223
224status_t DeviceHalAidl::prepareToOpenStream(
225 int32_t aidlHandle, const AudioDevice& aidlDevice, const AudioIoFlags& aidlFlags,
226 struct audio_config* config,
227 Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig) {
228 const bool isInput = aidlFlags.getTag() == AudioIoFlags::Tag::input;
229 // Find / create AudioPortConfigs for the device port and the mix port,
230 // then find / create a patch between them, and open a stream on the mix port.
231 AudioPortConfig devicePortConfig;
232 bool created = false;
233 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, &devicePortConfig, &created));
234 if (created) {
235 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
236 }
237 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*aidlConfig, aidlFlags, aidlHandle,
238 mixPortConfig, &created));
239 if (created) {
240 cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
241 }
242 setConfigFromPortConfig(aidlConfig, *mixPortConfig);
243 AudioPatch patch;
244 if (isInput) {
245 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
246 {devicePortConfig.id}, {mixPortConfig->id}, &patch, &created));
247 } else {
248 RETURN_STATUS_IF_ERROR(findOrCreatePatch(
249 {mixPortConfig->id}, {devicePortConfig.id}, &patch, &created));
250 }
251 if (created) {
252 cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, patch.id);
253 }
254 if (aidlConfig->frameCount <= 0) {
255 aidlConfig->frameCount = patch.minimumStreamBufferSizeFrames;
256 }
257 *config = VALUE_OR_RETURN_STATUS(
258 ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(*aidlConfig, isInput));
259 return OK;
260}
261
Mikhail Naganov31d46652023-01-10 18:29:25 +0000262status_t DeviceHalAidl::openOutputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800263 audio_io_handle_t handle, audio_devices_t devices,
264 audio_output_flags_t flags, struct audio_config* config,
265 const char* address,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000266 sp<StreamOutHalInterface>* outStream) {
267 if (!outStream || !config) {
268 return BAD_VALUE;
269 }
270 TIME_CHECK();
271 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800272 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
273 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
274 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
275 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, false /*isInput*/));
276 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
277 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
278 int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
279 ::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
280 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
281 AudioPortConfig mixPortConfig;
282 Cleanups cleanups;
283 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, config,
284 &cleanups, &aidlConfig, &mixPortConfig));
285 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
286 args.portConfigId = mixPortConfig.id;
287 args.offloadInfo = aidlConfig.offloadInfo;
288 args.bufferSizeFrames = aidlConfig.frameCount;
289 ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
290 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
291 *outStream = sp<StreamOutHalAidl>::make(*config, std::move(ret.desc), std::move(ret.stream));
292 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000293 return OK;
294}
295
Mikhail Naganov31d46652023-01-10 18:29:25 +0000296status_t DeviceHalAidl::openInputStream(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800297 audio_io_handle_t handle, audio_devices_t devices,
298 struct audio_config* config, audio_input_flags_t flags,
299 const char* address, audio_source_t source,
300 audio_devices_t outputDevice, const char* outputDeviceAddress,
Mikhail Naganov31d46652023-01-10 18:29:25 +0000301 sp<StreamInHalInterface>* inStream) {
302 if (!inStream || !config) {
303 return BAD_VALUE;
304 }
305 TIME_CHECK();
306 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800307 int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
308 ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
309 AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
310 ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
311 AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
312 ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
313 int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
314 ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
315 AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
316 AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
317 ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
318 AudioPortConfig mixPortConfig;
319 Cleanups cleanups;
320 RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, config,
321 &cleanups, &aidlConfig, &mixPortConfig));
322 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
323 args.portConfigId = mixPortConfig.id;
324 RecordTrackMetadata aidlTrackMetadata{
325 .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
326 if (outputDevice != AUDIO_DEVICE_NONE) {
327 aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
328 ::aidl::android::legacy2aidl_audio_device_AudioDevice(
329 outputDevice, outputDeviceAddress));
330 }
331 args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
332 args.bufferSizeFrames = aidlConfig.frameCount;
333 ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
334 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
335 *inStream = sp<StreamInHalAidl>::make(*config, std::move(ret.desc), std::move(ret.stream));
336 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000337 return OK;
338}
339
340status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
341 *supportsPatches = true;
342 return OK;
343}
344
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800345status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
346 const struct audio_port_config* sources,
347 unsigned int num_sinks,
348 const struct audio_port_config* sinks,
349 audio_patch_handle_t* patch) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000350 TIME_CHECK();
351 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800352 if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
353 sources == nullptr || sinks == nullptr || patch == nullptr) {
354 return BAD_VALUE;
355 }
356 // Note that the patch handle (*patch) is provided by the framework.
357 // In tests it's possible that its value is AUDIO_PATCH_HANDLE_NONE.
358
359 // Upon conversion, mix port configs contain audio configuration, while
360 // device port configs contain device address. This data is used to find
361 // or create HAL configs.
362 std::vector<AudioPortConfig> aidlSources, aidlSinks;
363 for (unsigned int i = 0; i < num_sources; ++i) {
364 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
365 sources[i].role, sources[i].type)) ==
366 ::aidl::android::AudioPortDirection::INPUT;
367 aidlSources.push_back(VALUE_OR_RETURN_STATUS(
368 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
369 sources[i], isInput, 0)));
370 }
371 for (unsigned int i = 0; i < num_sinks; ++i) {
372 bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
373 sinks[i].role, sinks[i].type)) ==
374 ::aidl::android::AudioPortDirection::INPUT;
375 aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
376 ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
377 sinks[i], isInput, 0)));
378 }
379 Cleanups cleanups;
380 auto existingPatchIt = mPatches.end();
381 auto fwkHandlesIt = *patch != AUDIO_PATCH_HANDLE_NONE ?
382 mFwkHandles.find(*patch) : mFwkHandles.end();
383 AudioPatch aidlPatch;
384 if (fwkHandlesIt != mFwkHandles.end()) {
385 existingPatchIt = mPatches.find(fwkHandlesIt->second);
386 if (existingPatchIt != mPatches.end()) {
387 aidlPatch = existingPatchIt->second;
388 aidlPatch.sourcePortConfigIds.clear();
389 aidlPatch.sinkPortConfigIds.clear();
390 }
391 }
392 auto fillPortConfigs = [&](
393 const std::vector<AudioPortConfig>& configs, std::vector<int32_t>* ids) -> status_t {
394 for (const auto& s : configs) {
395 AudioPortConfig portConfig;
396 bool created = false;
397 RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(s, &portConfig, &created));
398 if (created) {
399 cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, portConfig.id);
400 }
401 ids->push_back(portConfig.id);
402 }
403 return OK;
404 };
405 RETURN_STATUS_IF_ERROR(fillPortConfigs(aidlSources, &aidlPatch.sourcePortConfigIds));
406 RETURN_STATUS_IF_ERROR(fillPortConfigs(aidlSinks, &aidlPatch.sinkPortConfigIds));
407 if (existingPatchIt != mPatches.end()) {
408 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
409 mModule->setAudioPatch(aidlPatch, &aidlPatch)));
410 existingPatchIt->second = aidlPatch;
411 } else {
412 bool created = false;
413 RETURN_STATUS_IF_ERROR(findOrCreatePatch(aidlPatch, &aidlPatch, &created));
414 // Since no cleanup of the patch is needed, 'created' is ignored.
415 if (fwkHandlesIt != mFwkHandles.end()) {
416 fwkHandlesIt->second = aidlPatch.id;
417 // Patch handle (*patch) stays the same.
418 } else {
419 if (*patch == AUDIO_PATCH_HANDLE_NONE) {
420 // This isn't good as the module can't provide a handle which is really unique.
421 // However, this situation should only happen in tests.
422 *patch = aidlPatch.id;
423 LOG_ALWAYS_FATAL_IF(mFwkHandles.count(*patch) > 0,
424 "%s: patch id %d clashes with another framework patch handle",
425 __func__, *patch);
426 }
427 mFwkHandles.emplace(*patch, aidlPatch.id);
428 }
429 }
430 cleanups.disarmAll();
Shunkai Yao51202502022-12-12 06:11:46 +0000431 return OK;
432}
433
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800434status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000435 TIME_CHECK();
436 if (!mModule) return NO_INIT;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800437 auto idMapIt = mFwkHandles.find(patch);
438 if (idMapIt == mFwkHandles.end()) {
439 return BAD_VALUE;
440 }
441 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->resetAudioPatch(idMapIt->second)));
442 mFwkHandles.erase(idMapIt);
Shunkai Yao51202502022-12-12 06:11:46 +0000443 return OK;
444}
445
Mikhail Naganov31d46652023-01-10 18:29:25 +0000446status_t DeviceHalAidl::getAudioPort(struct audio_port* port __unused) {
447 TIME_CHECK();
448 ALOGE("%s not implemented yet", __func__);
449 return INVALID_OPERATION;
450}
451
452status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port __unused) {
453 TIME_CHECK();
454 ALOGE("%s not implemented yet", __func__);
455 return INVALID_OPERATION;
456}
457
458status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config __unused) {
459 TIME_CHECK();
460 if (!mModule) return NO_INIT;
461 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000462 return OK;
463}
464
465status_t DeviceHalAidl::getMicrophones(
Mikhail Naganov31d46652023-01-10 18:29:25 +0000466 std::vector<audio_microphone_characteristic_t>* microphones __unused) {
467 TIME_CHECK();
468 if (!mModule) return NO_INIT;
469 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000470 return OK;
471}
472
Mikhail Naganov31d46652023-01-10 18:29:25 +0000473status_t DeviceHalAidl::addDeviceEffect(audio_port_handle_t device __unused,
474 sp<EffectHalInterface> effect) {
Shunkai Yao51202502022-12-12 06:11:46 +0000475 if (!effect) {
476 return BAD_VALUE;
477 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000478 TIME_CHECK();
479 if (!mModule) return NO_INIT;
480 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000481 return OK;
482}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000483status_t DeviceHalAidl::removeDeviceEffect(audio_port_handle_t device __unused,
Shunkai Yao51202502022-12-12 06:11:46 +0000484 sp<EffectHalInterface> effect) {
485 if (!effect) {
486 return BAD_VALUE;
487 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000488 TIME_CHECK();
489 if (!mModule) return NO_INIT;
490 ALOGE("%s not implemented yet", __func__);
Shunkai Yao51202502022-12-12 06:11:46 +0000491 return OK;
492}
493
494status_t DeviceHalAidl::getMmapPolicyInfos(
495 media::audio::common::AudioMMapPolicyType policyType __unused,
496 std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos __unused) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000497 TIME_CHECK();
Shunkai Yao51202502022-12-12 06:11:46 +0000498 ALOGE("%s not implemented yet", __func__);
499 return OK;
500}
501
502int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000503 TIME_CHECK();
Shunkai Yao51202502022-12-12 06:11:46 +0000504 ALOGE("%s not implemented yet", __func__);
505 return OK;
506}
507
508int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000509 TIME_CHECK();
Shunkai Yao51202502022-12-12 06:11:46 +0000510 ALOGE("%s not implemented yet", __func__);
511 return OK;
512}
513
514error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000515 TIME_CHECK();
Shunkai Yao51202502022-12-12 06:11:46 +0000516 ALOGE("%s not implemented yet", __func__);
517 return base::unexpected(INVALID_OPERATION);
518}
519
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000520status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
521 TIME_CHECK();
522 if (!mModule) return NO_INIT;
523 return mModule->dump(fd, Args(args).args(), args.size());
Shunkai Yao51202502022-12-12 06:11:46 +0000524};
525
Mikhail Naganov31d46652023-01-10 18:29:25 +0000526int32_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports __unused) {
527 TIME_CHECK();
Shunkai Yao51202502022-12-12 06:11:46 +0000528 ALOGE("%s not implemented yet", __func__);
529 return INVALID_OPERATION;
530}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000531
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800532status_t DeviceHalAidl::createPortConfig(const AudioPortConfig& requestedPortConfig,
533 AudioPortConfig* appliedPortConfig) {
534 TIME_CHECK();
535 bool applied = false;
536 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
537 requestedPortConfig, appliedPortConfig, &applied)));
538 if (!applied) {
539 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
540 *appliedPortConfig, appliedPortConfig, &applied)));
541 if (!applied) {
542 ALOGE("%s: module %s did not apply suggested config %s",
543 __func__, mInstance.c_str(), appliedPortConfig->toString().c_str());
544 return NO_INIT;
545 }
546 }
547 mPortConfigs.emplace(appliedPortConfig->id, *appliedPortConfig);
548 return OK;
549}
550
551status_t DeviceHalAidl::findOrCreatePatch(
552 const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
553 std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
554 requestedPatch.sourcePortConfigIds.end());
555 std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
556 requestedPatch.sinkPortConfigIds.end());
557 return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
558}
559
560status_t DeviceHalAidl::findOrCreatePatch(
561 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
562 AudioPatch* patch, bool* created) {
563 auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
564 if (patchIt == mPatches.end()) {
565 TIME_CHECK();
566 AudioPatch requestedPatch, appliedPatch;
567 requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
568 sourcePortConfigIds.begin(), sourcePortConfigIds.end());
569 requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
570 sinkPortConfigIds.begin(), sinkPortConfigIds.end());
571 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
572 requestedPatch, &appliedPatch)));
573 patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
574 *created = true;
575 } else {
576 *created = false;
577 }
578 *patch = patchIt->second;
579 return OK;
580}
581
582status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device,
583 AudioPortConfig* portConfig, bool* created) {
584 auto portConfigIt = findPortConfig(device);
585 if (portConfigIt == mPortConfigs.end()) {
586 auto portsIt = findPort(device);
587 if (portsIt == mPorts.end()) {
588 ALOGE("%s: device port for device %s is not found in the module %s",
589 __func__, device.toString().c_str(), mInstance.c_str());
590 return BAD_VALUE;
591 }
592 AudioPortConfig requestedPortConfig;
593 requestedPortConfig.portId = portsIt->first;
594 AudioPortConfig appliedPortConfig;
595 RETURN_STATUS_IF_ERROR(createPortConfig(requestedPortConfig, &appliedPortConfig));
596 portConfigIt = mPortConfigs.insert(
597 mPortConfigs.end(), std::make_pair(appliedPortConfig.id, appliedPortConfig));
598 *created = true;
599 } else {
600 *created = false;
601 }
602 *portConfig = portConfigIt->second;
603 return OK;
604}
605
606status_t DeviceHalAidl::findOrCreatePortConfig(
607 const AudioConfig& config, const AudioIoFlags& flags, int32_t ioHandle,
608 AudioPortConfig* portConfig, bool* created) {
609 auto portConfigIt = findPortConfig(config, flags, ioHandle);
610 if (portConfigIt == mPortConfigs.end()) {
611 auto portsIt = findPort(config, flags);
612 if (portsIt == mPorts.end()) {
613 ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
614 __func__, config.toString().c_str(), flags.toString().c_str(),
615 mInstance.c_str());
616 return BAD_VALUE;
617 }
618 AudioPortConfig requestedPortConfig;
619 requestedPortConfig.portId = portsIt->first;
620 setPortConfigFromConfig(&requestedPortConfig, config);
621 AudioPortConfig appliedPortConfig;
622 RETURN_STATUS_IF_ERROR(createPortConfig(requestedPortConfig, &appliedPortConfig));
623 appliedPortConfig.ext.get<AudioPortExt::Tag::mix>().handle = ioHandle;
624 portConfigIt = mPortConfigs.insert(
625 mPortConfigs.end(), std::make_pair(appliedPortConfig.id, appliedPortConfig));
626 *created = true;
627 } else {
628 *created = false;
629 }
630 *portConfig = portConfigIt->second;
631 return OK;
632}
633
634status_t DeviceHalAidl::findOrCreatePortConfig(
635 const AudioPortConfig& requestedPortConfig, AudioPortConfig* portConfig, bool* created) {
636 using Tag = AudioPortExt::Tag;
637 if (requestedPortConfig.ext.getTag() == Tag::mix) {
638 if (const auto& p = requestedPortConfig;
639 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
640 !p.format.has_value() || !p.flags.has_value()) {
641 ALOGW("%s: provided mix port config is not fully specified: %s",
642 __func__, p.toString().c_str());
643 return BAD_VALUE;
644 }
645 AudioConfig config;
646 setConfigFromPortConfig(&config, requestedPortConfig);
647 return findOrCreatePortConfig(config, requestedPortConfig.flags.value(),
648 requestedPortConfig.ext.get<Tag::mix>().handle, portConfig, created);
649 } else if (requestedPortConfig.ext.getTag() == Tag::device) {
650 return findOrCreatePortConfig(
651 requestedPortConfig.ext.get<Tag::device>().device, portConfig, created);
652 }
653 ALOGW("%s: unsupported audio port config: %s",
654 __func__, requestedPortConfig.toString().c_str());
655 return BAD_VALUE;
656}
657
658DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
659 const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
660 return std::find_if(mPatches.begin(), mPatches.end(),
661 [&](const auto& pair) {
662 const auto& p = pair.second;
663 std::set<int32_t> patchSrcs(
664 p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
665 std::set<int32_t> patchSinks(
666 p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
667 return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
668}
669
670DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
671 using Tag = AudioPortExt::Tag;
672 return std::find_if(mPorts.begin(), mPorts.end(),
673 [&](const auto& pair) {
674 const auto& p = pair.second;
675 return p.ext.getTag() == Tag::device &&
676 p.ext.template get<Tag::device>().device == device; });
677}
678
679DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
680 const AudioConfig& config, const AudioIoFlags& flags) {
681 using Tag = AudioPortExt::Tag;
682 return std::find_if(mPorts.begin(), mPorts.end(),
683 [&](const auto& pair) {
684 const auto& p = pair.second;
685 return p.ext.getTag() == Tag::mix &&
686 p.flags == flags &&
687 std::find_if(p.profiles.begin(), p.profiles.end(),
688 [&](const auto& prof) {
689 return prof.format == config.base.format &&
690 std::find(prof.channelMasks.begin(),
691 prof.channelMasks.end(),
692 config.base.channelMask) !=
693 prof.channelMasks.end() &&
694 std::find(prof.sampleRates.begin(),
695 prof.sampleRates.end(),
696 config.base.sampleRate) !=
697 prof.sampleRates.end();
698 }) != p.profiles.end(); });
699}
700
701DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
702 using Tag = AudioPortExt::Tag;
703 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
704 [&](const auto& pair) {
705 const auto& p = pair.second;
706 return p.ext.getTag() == Tag::device &&
707 p.ext.template get<Tag::device>().device == device; });
708}
709
710DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
711 const AudioConfig& config, const AudioIoFlags& flags, int32_t ioHandle) {
712 using Tag = AudioPortExt::Tag;
713 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
714 [&](const auto& pair) {
715 const auto& p = pair.second;
716 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
717 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
718 !p.format.has_value() || !p.flags.has_value(),
719 "%s: stored mix port config is not fully specified: %s",
720 __func__, p.toString().c_str());
721 return p.ext.getTag() == Tag::mix &&
722 isConfigEqualToPortConfig(config, p) &&
723 p.flags.value() == flags &&
724 p.ext.template get<Tag::mix>().handle == ioHandle; });
725}
726/*
727DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
728 const AudioPortConfig& portConfig) {
729 using Tag = AudioPortExt::Tag;
730 if (portConfig.ext.getTag() == Tag::mix) {
731 return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
732 [&](const auto& pair) {
733 const auto& p = pair.second;
734 LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
735 !p.sampleRate.has_value() || !p.channelMask.has_value() ||
736 !p.format.has_value() || !p.flags.has_value(),
737 "%s: stored mix port config is not fully specified: %s",
738 __func__, p.toString().c_str());
739 return p.ext.getTag() == Tag::mix &&
740 (!portConfig.sampleRate.has_value() ||
741 p.sampleRate == portConfig.sampleRate) &&
742 (!portConfig.channelMask.has_value() ||
743 p.channelMask == portConfig.channelMask) &&
744 (!portConfig.format.has_value() || p.format == portConfig.format) &&
745 (!portConfig.flags.has_value() || p.flags == portConfig.flags) &&
746 p.ext.template get<Tag::mix>().handle ==
747 portConfig.ext.template get<Tag::mix>().handle; });
748 } else if (portConfig.ext.getTag() == Tag::device) {
749 return findPortConfig(portConfig.ext.get<Tag::device>().device);
750 }
751 return mPortConfigs.end();
752}
753*/
754void DeviceHalAidl::resetPatch(int32_t patchId) {
755 if (auto it = mPatches.find(patchId); it != mPatches.end()) {
756 mPatches.erase(it);
757 TIME_CHECK();
758 if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
759 ALOGE("%s: error while resetting patch %d: %s",
760 __func__, patchId, status.getDescription().c_str());
761 }
762 return;
763 }
764 ALOGE("%s: patch id %d not found", __func__, patchId);
765}
766
767void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
768 if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
769 mPortConfigs.erase(it);
770 TIME_CHECK();
771 if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
772 !status.isOk()) {
773 ALOGE("%s: error while resetting port config %d: %s",
774 __func__, portConfigId, status.getDescription().c_str());
775 }
776 return;
777 }
778 ALOGE("%s: port config id %d not found", __func__, portConfigId);
779}
780
Mikhail Naganov31d46652023-01-10 18:29:25 +0000781} // namespace android