blob: e74fc16a7c1eb03a8fee83d031baa5ac6ec49acf [file] [log] [blame]
Mikhail Naganov31d46652023-01-10 18:29:25 +00001/*
2 * Copyright (C) 2023 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 "StreamHalAidl"
18//#define LOG_NDEBUG 0
19
Mikhail Naganov89a9f742023-01-30 12:33:18 -080020#include <algorithm>
21#include <cstdint>
22
Mikhail Naganov89a9f742023-01-30 12:33:18 -080023#include <audio_utils/clock.h>
Mikhail Naganovcad0afe2023-03-10 14:25:57 -080024#include <media/AidlConversion.h>
Mikhail Naganovddc91b42023-04-14 14:35:30 -070025#include <media/AidlConversionCore.h>
David Lia0ad9f02023-03-02 21:46:19 +080026#include <media/AidlConversionCppNdk.h>
Mikhail Naganovb6e57752023-03-08 18:12:47 -080027#include <media/AidlConversionNdk.h>
David Lia6fb5752023-02-23 15:32:47 +000028#include <media/AidlConversionUtil.h>
David Lia0ad9f02023-03-02 21:46:19 +080029#include <media/AudioParameter.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000030#include <mediautils/TimeCheck.h>
David Lia0ad9f02023-03-02 21:46:19 +080031#include <system/audio.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000032#include <utils/Log.h>
33
34#include "DeviceHalAidl.h"
Mikhail Naganova82a69d2023-06-14 16:31:32 -070035#include "EffectHalAidl.h"
Mikhail Naganov31d46652023-01-10 18:29:25 +000036#include "StreamHalAidl.h"
37
David Lia6fb5752023-02-23 15:32:47 +000038using ::aidl::android::aidl_utils::statusTFromBinderStatus;
Mikhail Naganovb6e57752023-03-08 18:12:47 -080039using ::aidl::android::hardware::audio::common::PlaybackTrackMetadata;
40using ::aidl::android::hardware::audio::common::RecordTrackMetadata;
Mikhail Naganov31d46652023-01-10 18:29:25 +000041using ::aidl::android::hardware::audio::core::IStreamCommon;
42using ::aidl::android::hardware::audio::core::IStreamIn;
43using ::aidl::android::hardware::audio::core::IStreamOut;
44using ::aidl::android::hardware::audio::core::StreamDescriptor;
David Li9cf5e622023-03-21 00:51:10 +080045using ::aidl::android::hardware::audio::core::MmapBufferDescriptor;
Mikhail Naganovcad0afe2023-03-10 14:25:57 -080046using ::aidl::android::media::audio::common::MicrophoneDynamicInfo;
Mikhail Naganove7a26ad2023-05-25 17:36:48 -070047using ::aidl::android::media::audio::IHalAdapterVendorExtension;
Mikhail Naganov31d46652023-01-10 18:29:25 +000048
49namespace android {
50
Mikhail Naganov89a9f742023-01-30 12:33:18 -080051using HalCommand = StreamDescriptor::Command;
52namespace {
53template<HalCommand::Tag cmd> HalCommand makeHalCommand() {
54 return HalCommand::make<cmd>(::aidl::android::media::audio::common::Void{});
55}
56template<HalCommand::Tag cmd, typename T> HalCommand makeHalCommand(T data) {
57 return HalCommand::make<cmd>(data);
58}
59} // namespace
60
Mikhail Naganovfab697c2023-01-11 19:33:13 +000061// static
62template<class T>
63std::shared_ptr<IStreamCommon> StreamHalAidl::getStreamCommon(const std::shared_ptr<T>& stream) {
64 std::shared_ptr<::aidl::android::hardware::audio::core::IStreamCommon> streamCommon;
65 if (stream != nullptr) {
66 if (ndk::ScopedAStatus status = stream->getStreamCommon(&streamCommon);
67 !status.isOk()) {
68 ALOGE("%s: failed to retrieve IStreamCommon instance: %s", __func__,
69 status.getDescription().c_str());
70 }
71 }
72 return streamCommon;
73}
74
Mikhail Naganov31d46652023-01-10 18:29:25 +000075StreamHalAidl::StreamHalAidl(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080076 std::string_view className, bool isInput, const audio_config& config,
Mikhail Naganov89a9f742023-01-30 12:33:18 -080077 int32_t nominalLatency, StreamContextAidl&& context,
Mikhail Naganove7a26ad2023-05-25 17:36:48 -070078 const std::shared_ptr<IStreamCommon>& stream,
79 const std::shared_ptr<IHalAdapterVendorExtension>& vext)
Mikhail Naganov31d46652023-01-10 18:29:25 +000080 : ConversionHelperAidl(className),
81 mIsInput(isInput),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080082 mConfig(configToBase(config)),
Mikhail Naganov89a9f742023-01-30 12:33:18 -080083 mContext(std::move(context)),
Mikhail Naganove7a26ad2023-05-25 17:36:48 -070084 mStream(stream),
85 mVendorExt(vext) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -080086 {
87 std::lock_guard l(mLock);
88 mLastReply.latencyMs = nominalLatency;
89 }
Mikhail Naganov31d46652023-01-10 18:29:25 +000090 // Instrument audio signal power logging.
91 // Note: This assumes channel mask, format, and sample rate do not change after creation.
92 if (audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
93 /* mStreamPowerLog.isUserDebugOrEngBuild() && */
94 StreamHalAidl::getAudioProperties(&config) == NO_ERROR) {
95 mStreamPowerLog.init(config.sample_rate, config.channel_mask, config.format);
96 }
97}
98
99StreamHalAidl::~StreamHalAidl() {
100 if (mStream != nullptr) {
101 ndk::ScopedAStatus status = mStream->close();
102 ALOGE_IF(!status.isOk(), "%s: status %s", __func__, status.getDescription().c_str());
103 }
104}
105
106status_t StreamHalAidl::getBufferSize(size_t *size) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800107 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000108 if (size == nullptr) {
109 return BAD_VALUE;
110 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800111 if (mContext.getFrameSizeBytes() == 0 || mContext.getBufferSizeFrames() == 0 ||
112 !mStream) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000113 return NO_INIT;
114 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800115 *size = mContext.getBufferSizeBytes();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000116 return OK;
117}
118
119status_t StreamHalAidl::getAudioProperties(audio_config_base_t *configBase) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800120 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000121 if (configBase == nullptr) {
122 return BAD_VALUE;
123 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800124 if (!mStream) return NO_INIT;
125 *configBase = mConfig;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000126 return OK;
127}
128
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700129status_t StreamHalAidl::setParameters(const String8& kvPairs) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000130 TIME_CHECK();
131 if (!mStream) return NO_INIT;
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700132 AudioParameter parameters(kvPairs);
133 ALOGD("%s: parameters: %s", __func__, parameters.toString().c_str());
134
135 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
136 parameters, String8(AudioParameter::keyStreamHwAvSync),
137 [&](int hwAvSyncId) {
138 return statusTFromBinderStatus(mStream->updateHwAvSyncId(hwAvSyncId));
139 }));
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700140 return parseAndSetVendorParameters(mVendorExt, mStream, parameters);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000141}
142
143status_t StreamHalAidl::getParameters(const String8& keys __unused, String8 *values) {
144 TIME_CHECK();
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700145 if (!mStream) return NO_INIT;
146 if (values == nullptr) {
147 return BAD_VALUE;
148 }
149 AudioParameter parameterKeys(keys), result;
150 *values = result.toString();
151 return parseAndGetVendorParameters(mVendorExt, mStream, parameterKeys, values);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000152}
153
154status_t StreamHalAidl::getFrameSize(size_t *size) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800155 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000156 if (size == nullptr) {
157 return BAD_VALUE;
158 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800159 if (mContext.getFrameSizeBytes() == 0 || !mStream) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000160 return NO_INIT;
161 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800162 *size = mContext.getFrameSizeBytes();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000163 return OK;
164}
165
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700166status_t StreamHalAidl::addEffect(sp<EffectHalInterface> effect) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800167 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000168 TIME_CHECK();
169 if (!mStream) return NO_INIT;
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700170 if (effect == nullptr) {
171 return BAD_VALUE;
172 }
173 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
174 return statusTFromBinderStatus(mStream->addEffect(aidlEffect->getIEffect()));
Mikhail Naganov31d46652023-01-10 18:29:25 +0000175}
176
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700177status_t StreamHalAidl::removeEffect(sp<EffectHalInterface> effect) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800178 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000179 TIME_CHECK();
180 if (!mStream) return NO_INIT;
Mikhail Naganova82a69d2023-06-14 16:31:32 -0700181 if (effect == nullptr) {
182 return BAD_VALUE;
183 }
184 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
185 return statusTFromBinderStatus(mStream->removeEffect(aidlEffect->getIEffect()));
Mikhail Naganov31d46652023-01-10 18:29:25 +0000186}
187
188status_t StreamHalAidl::standby() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800189 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000190 TIME_CHECK();
191 if (!mStream) return NO_INIT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800192 const auto state = getState();
193 StreamDescriptor::Reply reply;
194 switch (state) {
195 case StreamDescriptor::State::ACTIVE:
Mikhail Naganove2084702023-09-28 14:37:12 -0700196 RETURN_STATUS_IF_ERROR(pause(&reply));
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800197 if (reply.state != StreamDescriptor::State::PAUSED) {
198 ALOGE("%s: unexpected stream state: %s (expected PAUSED)",
199 __func__, toString(reply.state).c_str());
200 return INVALID_OPERATION;
201 }
202 FALLTHROUGH_INTENDED;
203 case StreamDescriptor::State::PAUSED:
204 case StreamDescriptor::State::DRAIN_PAUSED:
Jasmine Cha105c66f2023-02-15 16:29:36 +0800205 if (mIsInput) return flush();
Mikhail Naganove2084702023-09-28 14:37:12 -0700206 RETURN_STATUS_IF_ERROR(flush(&reply));
Jasmine Cha105c66f2023-02-15 16:29:36 +0800207 if (reply.state != StreamDescriptor::State::IDLE) {
208 ALOGE("%s: unexpected stream state: %s (expected IDLE)",
209 __func__, toString(reply.state).c_str());
210 return INVALID_OPERATION;
211 }
212 FALLTHROUGH_INTENDED;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800213 case StreamDescriptor::State::IDLE:
Mikhail Naganove2084702023-09-28 14:37:12 -0700214 RETURN_STATUS_IF_ERROR(sendCommand(makeHalCommand<HalCommand::Tag::standby>(),
215 &reply, true /*safeFromNonWorkerThread*/));
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800216 if (reply.state != StreamDescriptor::State::STANDBY) {
217 ALOGE("%s: unexpected stream state: %s (expected STANDBY)",
218 __func__, toString(reply.state).c_str());
219 return INVALID_OPERATION;
220 }
221 FALLTHROUGH_INTENDED;
222 case StreamDescriptor::State::STANDBY:
223 return OK;
224 default:
225 ALOGE("%s: not supported from %s stream state %s",
226 __func__, mIsInput ? "input" : "output", toString(state).c_str());
227 return INVALID_OPERATION;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800228 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000229}
230
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000231status_t StreamHalAidl::dump(int fd, const Vector<String16>& args) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800232 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000233 TIME_CHECK();
234 if (!mStream) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000235 return mStream->dump(fd, Args(args).args(), args.size());
Mikhail Naganov31d46652023-01-10 18:29:25 +0000236}
237
238status_t StreamHalAidl::start() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800239 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000240 TIME_CHECK();
241 if (!mStream) return NO_INIT;
David Li9cf5e622023-03-21 00:51:10 +0800242 const auto state = getState();
243 StreamDescriptor::Reply reply;
244 if (state == StreamDescriptor::State::STANDBY) {
Mikhail Naganove2084702023-09-28 14:37:12 -0700245 RETURN_STATUS_IF_ERROR(sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply, true));
David Li9cf5e622023-03-21 00:51:10 +0800246 return sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), &reply, true);
247 }
248
249 return INVALID_OPERATION;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000250}
251
252status_t StreamHalAidl::stop() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800253 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800254 if (!mStream) return NO_INIT;
David Li9cf5e622023-03-21 00:51:10 +0800255 return standby();
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800256}
257
258status_t StreamHalAidl::getLatency(uint32_t *latency) {
259 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
260 if (!mStream) return NO_INIT;
261 StreamDescriptor::Reply reply;
Mikhail Naganove2084702023-09-28 14:37:12 -0700262 RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
Shunkai Yao2017dda2023-08-19 01:43:02 +0000263 *latency = std::clamp(std::max<int32_t>(0, reply.latencyMs), 1, 3000);
264 ALOGW_IF(reply.latencyMs != static_cast<int32_t>(*latency),
265 "Suspicious latency value reported by HAL: %d, clamped to %u", reply.latencyMs,
266 *latency);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800267 return OK;
268}
269
270status_t StreamHalAidl::getObservablePosition(int64_t *frames, int64_t *timestamp) {
271 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
272 if (!mStream) return NO_INIT;
273 StreamDescriptor::Reply reply;
Mikhail Naganove2084702023-09-28 14:37:12 -0700274 RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
275 *frames = std::max<int64_t>(0, reply.observable.frames);
276 *timestamp = std::max<int64_t>(0, reply.observable.timeNs);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800277 return OK;
278}
279
David Li9cf5e622023-03-21 00:51:10 +0800280status_t StreamHalAidl::getHardwarePosition(int64_t *frames, int64_t *timestamp) {
281 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
282 if (!mStream) return NO_INIT;
283 StreamDescriptor::Reply reply;
284 // TODO: switch to updateCountersIfNeeded once we sort out mWorkerTid initialization
Mikhail Naganove2084702023-09-28 14:37:12 -0700285 RETURN_STATUS_IF_ERROR(sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), &reply, true));
286 *frames = std::max<int64_t>(0, reply.hardware.frames);
287 *timestamp = std::max<int64_t>(0, reply.hardware.timeNs);
David Li9cf5e622023-03-21 00:51:10 +0800288 return OK;
289}
290
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800291status_t StreamHalAidl::getXruns(int32_t *frames) {
292 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
293 if (!mStream) return NO_INIT;
294 StreamDescriptor::Reply reply;
Mikhail Naganove2084702023-09-28 14:37:12 -0700295 RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
296 *frames = std::max<int32_t>(0, reply.xrunFrames);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800297 return OK;
298}
299
300status_t StreamHalAidl::transfer(void *buffer, size_t bytes, size_t *transferred) {
301 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
Shunkai Yaoc6308712023-02-22 17:53:04 +0000302 // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800303 if (!mStream || mContext.getDataMQ() == nullptr) return NO_INIT;
304 mWorkerTid.store(gettid(), std::memory_order_release);
305 // Switch the stream into an active state if needed.
306 // Note: in future we may add support for priming the audio pipeline
307 // with data prior to enabling output (thus we can issue a "burst" command in the "standby"
308 // stream state), however this scenario wasn't supported by the HIDL HAL.
309 if (getState() == StreamDescriptor::State::STANDBY) {
310 StreamDescriptor::Reply reply;
Mikhail Naganove2084702023-09-28 14:37:12 -0700311 RETURN_STATUS_IF_ERROR(sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply));
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800312 if (reply.state != StreamDescriptor::State::IDLE) {
313 ALOGE("%s: failed to get the stream out of standby, actual state: %s",
314 __func__, toString(reply.state).c_str());
315 return INVALID_OPERATION;
316 }
317 }
318 if (!mIsInput) {
319 bytes = std::min(bytes, mContext.getDataMQ()->availableToWrite());
320 }
321 StreamDescriptor::Command burst =
322 StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(bytes);
323 if (!mIsInput) {
324 if (!mContext.getDataMQ()->write(static_cast<const int8_t*>(buffer), bytes)) {
325 ALOGE("%s: failed to write %zu bytes to data MQ", __func__, bytes);
326 return NOT_ENOUGH_DATA;
327 }
328 }
329 StreamDescriptor::Reply reply;
Mikhail Naganove2084702023-09-28 14:37:12 -0700330 RETURN_STATUS_IF_ERROR(sendCommand(burst, &reply));
Jasmine Chaad99fb02023-02-10 12:52:58 +0800331 *transferred = reply.fmqByteCount;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800332 if (mIsInput) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800333 LOG_ALWAYS_FATAL_IF(*transferred > bytes,
334 "%s: HAL module read %zu bytes, which exceeds requested count %zu",
335 __func__, *transferred, bytes);
Jasmine Cha105c66f2023-02-15 16:29:36 +0800336 if (auto toRead = mContext.getDataMQ()->availableToRead();
337 toRead != 0 && !mContext.getDataMQ()->read(static_cast<int8_t*>(buffer), toRead)) {
338 ALOGE("%s: failed to read %zu bytes to data MQ", __func__, toRead);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800339 return NOT_ENOUGH_DATA;
340 }
341 }
342 mStreamPowerLog.log(buffer, *transferred);
343 return OK;
344}
345
346status_t StreamHalAidl::pause(StreamDescriptor::Reply* reply) {
347 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
348 TIME_CHECK();
349 if (!mStream) return NO_INIT;
350 return sendCommand(makeHalCommand<HalCommand::Tag::pause>(), reply,
351 true /*safeFromNonWorkerThread*/); // The workers stops its I/O activity first.
352}
353
354status_t StreamHalAidl::resume(StreamDescriptor::Reply* reply) {
355 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
356 TIME_CHECK();
357 if (!mStream) return NO_INIT;
358 if (mIsInput) {
359 return sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), reply);
360 } else {
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800361 if (mContext.isAsynchronous()) {
362 // Handle pause-flush-resume sequence. 'flush' from PAUSED goes to
363 // IDLE. We move here from IDLE to ACTIVE (same as 'start' from PAUSED).
364 const auto state = getState();
365 if (state == StreamDescriptor::State::IDLE) {
366 StreamDescriptor::Reply localReply{};
367 StreamDescriptor::Reply* innerReply = reply ?: &localReply;
Mikhail Naganove2084702023-09-28 14:37:12 -0700368 RETURN_STATUS_IF_ERROR(
369 sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), innerReply));
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800370 if (innerReply->state != StreamDescriptor::State::ACTIVE) {
371 ALOGE("%s: unexpected stream state: %s (expected ACTIVE)",
372 __func__, toString(innerReply->state).c_str());
373 return INVALID_OPERATION;
374 }
375 return OK;
376 }
377 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800378 return sendCommand(makeHalCommand<HalCommand::Tag::start>(), reply);
379 }
380}
381
382status_t StreamHalAidl::drain(bool earlyNotify, StreamDescriptor::Reply* reply) {
383 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
384 TIME_CHECK();
385 if (!mStream) return NO_INIT;
386 return sendCommand(makeHalCommand<HalCommand::Tag::drain>(
387 mIsInput ? StreamDescriptor::DrainMode::DRAIN_UNSPECIFIED :
388 earlyNotify ? StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY :
David Lia6fb5752023-02-23 15:32:47 +0000389 StreamDescriptor::DrainMode::DRAIN_ALL), reply,
390 true /*safeFromNonWorkerThread*/);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800391}
392
393status_t StreamHalAidl::flush(StreamDescriptor::Reply* reply) {
394 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
395 TIME_CHECK();
396 if (!mStream) return NO_INIT;
397 return sendCommand(makeHalCommand<HalCommand::Tag::flush>(), reply,
398 true /*safeFromNonWorkerThread*/); // The workers stops its I/O activity first.
399}
400
401status_t StreamHalAidl::exit() {
402 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000403 TIME_CHECK();
404 if (!mStream) return NO_INIT;
Andy Hungb72a5502023-03-27 15:53:06 -0700405 return statusTFromBinderStatus(mStream->prepareToClose());
Mikhail Naganov31d46652023-01-10 18:29:25 +0000406}
407
408status_t StreamHalAidl::createMmapBuffer(int32_t minSizeFrames __unused,
David Li9cf5e622023-03-21 00:51:10 +0800409 struct audio_mmap_buffer_info *info) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800410 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000411 TIME_CHECK();
412 if (!mStream) return NO_INIT;
David Li9cf5e622023-03-21 00:51:10 +0800413 if (!mContext.isMmapped()) {
414 return BAD_VALUE;
415 }
416 const MmapBufferDescriptor& bufferDescriptor = mContext.getMmapBufferDescriptor();
417 info->shared_memory_fd = bufferDescriptor.sharedMemory.fd.get();
418 info->buffer_size_frames = mContext.getBufferSizeFrames();
419 info->burst_size_frames = bufferDescriptor.burstSizeFrames;
420 info->flags = static_cast<audio_mmap_buffer_flag>(bufferDescriptor.flags);
421
Mikhail Naganov31d46652023-01-10 18:29:25 +0000422 return OK;
423}
424
David Li9cf5e622023-03-21 00:51:10 +0800425status_t StreamHalAidl::getMmapPosition(struct audio_mmap_position *position) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000426 TIME_CHECK();
427 if (!mStream) return NO_INIT;
David Li9cf5e622023-03-21 00:51:10 +0800428 if (!mContext.isMmapped()) {
429 return BAD_VALUE;
430 }
431 int64_t aidlPosition = 0, aidlTimestamp = 0;
Mikhail Naganove2084702023-09-28 14:37:12 -0700432 RETURN_STATUS_IF_ERROR(getHardwarePosition(&aidlPosition, &aidlTimestamp));
David Li9cf5e622023-03-21 00:51:10 +0800433 position->time_nanoseconds = aidlTimestamp;
434 position->position_frames = static_cast<int32_t>(aidlPosition);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000435 return OK;
436}
437
438status_t StreamHalAidl::setHalThreadPriority(int priority __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800439 // Obsolete, must be done by the HAL module.
Mikhail Naganov31d46652023-01-10 18:29:25 +0000440 return OK;
441}
442
Mikhail Naganov31d46652023-01-10 18:29:25 +0000443status_t StreamHalAidl::legacyCreateAudioPatch(const struct audio_port_config& port __unused,
444 std::optional<audio_source_t> source __unused,
445 audio_devices_t type __unused) {
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000446 // Obsolete since 'DeviceHalAidl.supportsAudioPatches' always returns 'true'.
447 return INVALID_OPERATION;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000448}
449
450status_t StreamHalAidl::legacyReleaseAudioPatch() {
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000451 // Obsolete since 'DeviceHalAidl.supportsAudioPatches' always returns 'true'.
452 return INVALID_OPERATION;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000453}
454
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800455status_t StreamHalAidl::sendCommand(
456 const ::aidl::android::hardware::audio::core::StreamDescriptor::Command &command,
457 ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply,
458 bool safeFromNonWorkerThread) {
Shunkai Yaoc6308712023-02-22 17:53:04 +0000459 // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800460 if (!safeFromNonWorkerThread) {
461 const pid_t workerTid = mWorkerTid.load(std::memory_order_acquire);
462 LOG_ALWAYS_FATAL_IF(workerTid != gettid(),
463 "%s %s: must be invoked from the worker thread (%d)",
464 __func__, command.toString().c_str(), workerTid);
465 }
466 if (!mContext.getCommandMQ()->writeBlocking(&command, 1)) {
467 ALOGE("%s: failed to write command %s to MQ", __func__, command.toString().c_str());
468 return NOT_ENOUGH_DATA;
469 }
470 StreamDescriptor::Reply localReply{};
471 if (reply == nullptr) {
472 reply = &localReply;
473 }
474 if (!mContext.getReplyMQ()->readBlocking(reply, 1)) {
475 ALOGE("%s: failed to read from reply MQ, command %s", __func__, command.toString().c_str());
476 return NOT_ENOUGH_DATA;
477 }
478 {
479 std::lock_guard l(mLock);
Mikhail Naganove2084702023-09-28 14:37:12 -0700480 // Not every command replies with 'latencyMs' field filled out, substitute the last
481 // returned value in that case.
482 if (reply->latencyMs <= 0) {
483 reply->latencyMs = mLastReply.latencyMs;
484 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800485 mLastReply = *reply;
486 }
487 switch (reply->status) {
488 case STATUS_OK: return OK;
489 case STATUS_BAD_VALUE: return BAD_VALUE;
490 case STATUS_INVALID_OPERATION: return INVALID_OPERATION;
491 case STATUS_NOT_ENOUGH_DATA: return NOT_ENOUGH_DATA;
492 default:
493 ALOGE("%s: unexpected status %d returned for command %s",
494 __func__, reply->status, command.toString().c_str());
495 return INVALID_OPERATION;
496 }
497}
498
499status_t StreamHalAidl::updateCountersIfNeeded(
500 ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply) {
501 if (mWorkerTid.load(std::memory_order_acquire) == gettid()) {
502 if (const auto state = getState(); state != StreamDescriptor::State::ACTIVE &&
503 state != StreamDescriptor::State::DRAINING &&
504 state != StreamDescriptor::State::TRANSFERRING) {
505 return sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), reply);
506 }
507 }
508 if (reply != nullptr) {
509 std::lock_guard l(mLock);
510 *reply = mLastReply;
511 }
512 return OK;
513}
514
Mikhail Naganovb6e57752023-03-08 18:12:47 -0800515// static
Mikhail Naganov19418e32023-03-10 17:55:14 -0800516ConversionResult<::aidl::android::hardware::audio::common::SourceMetadata>
Mikhail Naganovb6e57752023-03-08 18:12:47 -0800517StreamOutHalAidl::legacy2aidl_SourceMetadata(const StreamOutHalInterface::SourceMetadata& legacy) {
518 ::aidl::android::hardware::audio::common::SourceMetadata aidl;
519 aidl.tracks = VALUE_OR_RETURN(
520 ::aidl::android::convertContainer<std::vector<PlaybackTrackMetadata>>(
521 legacy.tracks,
522 ::aidl::android::legacy2aidl_playback_track_metadata_v7_PlaybackTrackMetadata));
523 return aidl;
524}
525
Mikhail Naganov31d46652023-01-10 18:29:25 +0000526StreamOutHalAidl::StreamOutHalAidl(
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800527 const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700528 const std::shared_ptr<IStreamOut>& stream,
529 const std::shared_ptr<IHalAdapterVendorExtension>& vext,
530 const sp<CallbackBroker>& callbackBroker)
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800531 : StreamHalAidl("StreamOutHalAidl", false /*isInput*/, config, nominalLatency,
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700532 std::move(context), getStreamCommon(stream), vext),
David Lia0ad9f02023-03-02 21:46:19 +0800533 mStream(stream), mCallbackBroker(callbackBroker) {
534 // Initialize the offload metadata
535 mOffloadMetadata.sampleRate = static_cast<int32_t>(config.sample_rate);
536 mOffloadMetadata.channelMask = VALUE_OR_FATAL(
Mikhail Naganov893b7c22023-03-13 15:48:11 -0700537 ::aidl::android::legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
538 config.channel_mask, false));
David Lia0ad9f02023-03-02 21:46:19 +0800539 mOffloadMetadata.averageBitRatePerSecond = static_cast<int32_t>(config.offload_info.bit_rate);
540}
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800541
542StreamOutHalAidl::~StreamOutHalAidl() {
543 if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
544 broker->clearCallbacks(this);
545 }
546}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000547
David Lia0ad9f02023-03-02 21:46:19 +0800548status_t StreamOutHalAidl::setParameters(const String8& kvPairs) {
549 if (!mStream) return NO_INIT;
550
551 AudioParameter parameters(kvPairs);
Mikhail Naganovccc82112023-04-27 18:14:15 -0700552 ALOGD("%s: parameters: \"%s\"", __func__, parameters.toString().c_str());
David Lia0ad9f02023-03-02 21:46:19 +0800553
Mikhail Naganovb6e57752023-03-08 18:12:47 -0800554 if (status_t status = filterAndUpdateOffloadMetadata(parameters); status != OK) {
Mikhail Naganovccc82112023-04-27 18:14:15 -0700555 ALOGW("%s: filtering or updating offload metadata failed: %d", __func__, status);
David Lia0ad9f02023-03-02 21:46:19 +0800556 }
557
558 return StreamHalAidl::setParameters(parameters.toString());
559}
560
Mikhail Naganov31d46652023-01-10 18:29:25 +0000561status_t StreamOutHalAidl::getLatency(uint32_t *latency) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800562 return StreamHalAidl::getLatency(latency);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000563}
564
David Lia6fb5752023-02-23 15:32:47 +0000565status_t StreamOutHalAidl::setVolume(float left, float right) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000566 TIME_CHECK();
567 if (!mStream) return NO_INIT;
David Lia6fb5752023-02-23 15:32:47 +0000568 return statusTFromBinderStatus(mStream->setHwVolume({left, right}));
Mikhail Naganov31d46652023-01-10 18:29:25 +0000569}
570
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700571status_t StreamOutHalAidl::selectPresentation(int presentationId, int programId) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000572 TIME_CHECK();
573 if (!mStream) return NO_INIT;
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700574 return statusTFromBinderStatus(mStream->selectPresentation(presentationId, programId));
Mikhail Naganov31d46652023-01-10 18:29:25 +0000575}
576
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800577status_t StreamOutHalAidl::write(const void *buffer, size_t bytes, size_t *written) {
578 if (buffer == nullptr || written == nullptr) {
579 return BAD_VALUE;
580 }
581 // For the output scenario, 'transfer' does not modify the buffer.
582 return transfer(const_cast<void*>(buffer), bytes, written);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000583}
584
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800585status_t StreamOutHalAidl::getRenderPosition(uint32_t *dspFrames) {
586 if (dspFrames == nullptr) {
587 return BAD_VALUE;
588 }
589 int64_t aidlFrames = 0, aidlTimestamp = 0;
Mikhail Naganove2084702023-09-28 14:37:12 -0700590 RETURN_STATUS_IF_ERROR(getObservablePosition(&aidlFrames, &aidlTimestamp));
591 *dspFrames = static_cast<uint32_t>(aidlFrames);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000592 return OK;
593}
594
595status_t StreamOutHalAidl::getNextWriteTimestamp(int64_t *timestamp __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800596 // Obsolete, use getPresentationPosition.
597 return INVALID_OPERATION;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000598}
599
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800600status_t StreamOutHalAidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000601 TIME_CHECK();
602 if (!mStream) return NO_INIT;
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800603 if (!mContext.isAsynchronous()) {
604 ALOGE("%s: the callback is intended for asynchronous streams only", __func__);
605 return INVALID_OPERATION;
606 }
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800607 if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
608 if (auto cb = callback.promote(); cb != nullptr) {
609 broker->setStreamOutCallback(this, cb);
610 } else {
611 // It is expected that the framework never passes a null pointer.
612 // In the AIDL model callbacks can't be "unregistered".
613 LOG_ALWAYS_FATAL("%s: received an expired or null callback pointer", __func__);
614 }
615 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000616 return OK;
617}
618
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800619status_t StreamOutHalAidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
620 if (supportsPause == nullptr || supportsResume == nullptr) {
621 return BAD_VALUE;
622 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000623 TIME_CHECK();
624 if (!mStream) return NO_INIT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800625 *supportsPause = *supportsResume = true;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000626 return OK;
627}
628
629status_t StreamOutHalAidl::pause() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800630 return StreamHalAidl::pause();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000631}
632
633status_t StreamOutHalAidl::resume() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800634 return StreamHalAidl::resume();
635}
636
637status_t StreamOutHalAidl::supportsDrain(bool *supportsDrain) {
638 if (supportsDrain == nullptr) {
639 return BAD_VALUE;
640 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000641 TIME_CHECK();
642 if (!mStream) return NO_INIT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800643 *supportsDrain = true;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000644 return OK;
645}
646
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800647status_t StreamOutHalAidl::drain(bool earlyNotify) {
648 return StreamHalAidl::drain(earlyNotify);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000649}
650
651status_t StreamOutHalAidl::flush() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800652 return StreamHalAidl::flush();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000653}
654
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800655status_t StreamOutHalAidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
656 if (frames == nullptr || timestamp == nullptr) {
657 return BAD_VALUE;
658 }
659 int64_t aidlFrames = 0, aidlTimestamp = 0;
Mikhail Naganove2084702023-09-28 14:37:12 -0700660 RETURN_STATUS_IF_ERROR(getObservablePosition(&aidlFrames, &aidlTimestamp));
661 *frames = aidlFrames;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800662 timestamp->tv_sec = aidlTimestamp / NANOS_PER_SECOND;
663 timestamp->tv_nsec = aidlTimestamp - timestamp->tv_sec * NANOS_PER_SECOND;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000664 return OK;
665}
666
667status_t StreamOutHalAidl::updateSourceMetadata(
Mikhail Naganovb6e57752023-03-08 18:12:47 -0800668 const StreamOutHalInterface::SourceMetadata& sourceMetadata) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000669 TIME_CHECK();
670 if (!mStream) return NO_INIT;
Mikhail Naganovb6e57752023-03-08 18:12:47 -0800671 ::aidl::android::hardware::audio::common::SourceMetadata aidlMetadata =
672 VALUE_OR_RETURN_STATUS(legacy2aidl_SourceMetadata(sourceMetadata));
673 return statusTFromBinderStatus(mStream->updateMetadata(aidlMetadata));
Mikhail Naganov31d46652023-01-10 18:29:25 +0000674}
675
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700676status_t StreamOutHalAidl::getDualMonoMode(audio_dual_mono_mode_t* mode) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800677 TIME_CHECK();
678 if (!mStream) return NO_INIT;
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700679 if (mode == nullptr) {
680 return BAD_VALUE;
681 }
682 ::aidl::android::media::audio::common::AudioDualMonoMode aidlMode;
683 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mStream->getDualMonoMode(&aidlMode)));
684 *mode = VALUE_OR_RETURN_STATUS(
685 ::aidl::android::aidl2legacy_AudioDualMonoMode_audio_dual_mono_mode_t(aidlMode));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800686 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000687}
688
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700689status_t StreamOutHalAidl::setDualMonoMode(audio_dual_mono_mode_t mode) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800690 TIME_CHECK();
691 if (!mStream) return NO_INIT;
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700692 ::aidl::android::media::audio::common::AudioDualMonoMode aidlMode = VALUE_OR_RETURN_STATUS(
693 ::aidl::android::legacy2aidl_audio_dual_mono_mode_t_AudioDualMonoMode(mode));
694 return statusTFromBinderStatus(mStream->setDualMonoMode(aidlMode));
695}
696
697status_t StreamOutHalAidl::getAudioDescriptionMixLevel(float* leveldB) {
698 TIME_CHECK();
699 if (!mStream) return NO_INIT;
700 if (leveldB == nullptr) {
701 return BAD_VALUE;
702 }
703 return statusTFromBinderStatus(mStream->getAudioDescriptionMixLevel(leveldB));
704}
705
706status_t StreamOutHalAidl::setAudioDescriptionMixLevel(float leveldB) {
707 TIME_CHECK();
708 if (!mStream) return NO_INIT;
709 return statusTFromBinderStatus(mStream->setAudioDescriptionMixLevel(leveldB));
710}
711
712status_t StreamOutHalAidl::getPlaybackRateParameters(audio_playback_rate_t* playbackRate) {
713 TIME_CHECK();
714 if (!mStream) return NO_INIT;
715 if (playbackRate == nullptr) {
716 return BAD_VALUE;
717 }
718 ::aidl::android::media::audio::common::AudioPlaybackRate aidlRate;
719 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mStream->getPlaybackRateParameters(&aidlRate)));
720 *playbackRate = VALUE_OR_RETURN_STATUS(
721 ::aidl::android::aidl2legacy_AudioPlaybackRate_audio_playback_rate_t(aidlRate));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800722 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000723}
724
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700725status_t StreamOutHalAidl::setPlaybackRateParameters(const audio_playback_rate_t& playbackRate) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800726 TIME_CHECK();
727 if (!mStream) return NO_INIT;
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700728 ::aidl::android::media::audio::common::AudioPlaybackRate aidlRate = VALUE_OR_RETURN_STATUS(
729 ::aidl::android::legacy2aidl_audio_playback_rate_t_AudioPlaybackRate(playbackRate));
730 return statusTFromBinderStatus(mStream->setPlaybackRateParameters(aidlRate));
Mikhail Naganov31d46652023-01-10 18:29:25 +0000731}
732
733status_t StreamOutHalAidl::setEventCallback(
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800734 const sp<StreamOutHalInterfaceEventCallback>& callback) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800735 TIME_CHECK();
736 if (!mStream) return NO_INIT;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800737 if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
738 broker->setStreamOutEventCallback(this, callback);
739 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800740 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000741}
742
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700743status_t StreamOutHalAidl::setLatencyMode(audio_latency_mode_t mode) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800744 TIME_CHECK();
745 if (!mStream) return NO_INIT;
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700746 ::aidl::android::media::audio::common::AudioLatencyMode aidlMode = VALUE_OR_RETURN_STATUS(
747 ::aidl::android::legacy2aidl_audio_latency_mode_t_AudioLatencyMode(mode));
748 return statusTFromBinderStatus(mStream->setLatencyMode(aidlMode));
Mikhail Naganov31d46652023-01-10 18:29:25 +0000749};
750
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700751status_t StreamOutHalAidl::getRecommendedLatencyModes(std::vector<audio_latency_mode_t> *modes) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800752 TIME_CHECK();
753 if (!mStream) return NO_INIT;
Mikhail Naganov3ac95c92023-04-12 13:14:30 -0700754 if (modes == nullptr) {
755 return BAD_VALUE;
756 }
757 std::vector<::aidl::android::media::audio::common::AudioLatencyMode> aidlModes;
758 RETURN_STATUS_IF_ERROR(
759 statusTFromBinderStatus(mStream->getRecommendedLatencyModes(&aidlModes)));
760 *modes = VALUE_OR_RETURN_STATUS(
761 ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
762 aidlModes,
763 ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800764 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000765};
766
767status_t StreamOutHalAidl::setLatencyModeCallback(
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800768 const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800769 TIME_CHECK();
770 if (!mStream) return NO_INIT;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800771 if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
772 broker->setStreamOutLatencyModeCallback(this, callback);
773 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800774 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000775};
776
Mikhail Naganov31d46652023-01-10 18:29:25 +0000777status_t StreamOutHalAidl::exit() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800778 return StreamHalAidl::exit();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000779}
780
David Lia0ad9f02023-03-02 21:46:19 +0800781status_t StreamOutHalAidl::filterAndUpdateOffloadMetadata(AudioParameter &parameters) {
782 TIME_CHECK();
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700783 bool updateMetadata = false;
784 if (VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
785 parameters, String8(AudioParameter::keyOffloadCodecAverageBitRate),
786 [&](int value) {
787 return value > 0 ?
788 mOffloadMetadata.averageBitRatePerSecond = value, OK : BAD_VALUE;
789 }))) {
790 updateMetadata = true;
791 }
792 if (VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
793 parameters, String8(AudioParameter::keyOffloadCodecSampleRate),
794 [&](int value) {
795 return value > 0 ? mOffloadMetadata.sampleRate = value, OK : BAD_VALUE;
796 }))) {
797 updateMetadata = true;
798 }
799 if (VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
800 parameters, String8(AudioParameter::keyOffloadCodecChannels),
801 [&](int value) -> status_t {
802 if (value > 0) {
803 audio_channel_mask_t channel_mask = audio_channel_out_mask_from_count(
804 static_cast<uint32_t>(value));
805 if (channel_mask == AUDIO_CHANNEL_INVALID) return BAD_VALUE;
806 mOffloadMetadata.channelMask = VALUE_OR_RETURN_STATUS(
807 ::aidl::android::legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
808 channel_mask, false /*isInput*/));
809 }
810 return BAD_VALUE;
811 }))) {
812 updateMetadata = true;
813 }
814 if (VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
815 parameters, String8(AudioParameter::keyOffloadCodecDelaySamples),
816 [&](int value) {
817 // The legacy keys are misnamed, the value is in frames.
David Lif753e682023-09-14 23:13:34 +0000818 return value >= 0 ? mOffloadMetadata.delayFrames = value, OK : BAD_VALUE;
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700819 }))) {
820 updateMetadata = true;
821 }
822 if (VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
823 parameters, String8(AudioParameter::keyOffloadCodecPaddingSamples),
824 [&](int value) {
825 // The legacy keys are misnamed, the value is in frames.
David Lif753e682023-09-14 23:13:34 +0000826 return value >= 0 ? mOffloadMetadata.paddingFrames = value, OK : BAD_VALUE;
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700827 }))) {
828 updateMetadata = true;
829 }
830 if (updateMetadata) {
David Lia0ad9f02023-03-02 21:46:19 +0800831 ALOGD("%s set offload metadata %s", __func__, mOffloadMetadata.toString().c_str());
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700832 if (status_t status = statusTFromBinderStatus(
833 mStream->updateOffloadMetadata(mOffloadMetadata)); status != OK) {
David Lia0ad9f02023-03-02 21:46:19 +0800834 ALOGE("%s: updateOffloadMetadata failed %d", __func__, status);
835 return status;
836 }
837 }
838 return OK;
839}
840
Mikhail Naganovb6e57752023-03-08 18:12:47 -0800841// static
Mikhail Naganov19418e32023-03-10 17:55:14 -0800842ConversionResult<::aidl::android::hardware::audio::common::SinkMetadata>
Mikhail Naganovb6e57752023-03-08 18:12:47 -0800843StreamInHalAidl::legacy2aidl_SinkMetadata(const StreamInHalInterface::SinkMetadata& legacy) {
844 ::aidl::android::hardware::audio::common::SinkMetadata aidl;
845 aidl.tracks = VALUE_OR_RETURN(
846 ::aidl::android::convertContainer<std::vector<RecordTrackMetadata>>(
847 legacy.tracks,
848 ::aidl::android::legacy2aidl_record_track_metadata_v7_RecordTrackMetadata));
849 return aidl;
850}
851
Mikhail Naganov31d46652023-01-10 18:29:25 +0000852StreamInHalAidl::StreamInHalAidl(
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800853 const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700854 const std::shared_ptr<IStreamIn>& stream,
855 const std::shared_ptr<IHalAdapterVendorExtension>& vext,
856 const sp<MicrophoneInfoProvider>& micInfoProvider)
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800857 : StreamHalAidl("StreamInHalAidl", true /*isInput*/, config, nominalLatency,
Mikhail Naganove7a26ad2023-05-25 17:36:48 -0700858 std::move(context), getStreamCommon(stream), vext),
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800859 mStream(stream), mMicInfoProvider(micInfoProvider) {}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000860
Mikhail Naganovddc91b42023-04-14 14:35:30 -0700861status_t StreamInHalAidl::setGain(float gain) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000862 TIME_CHECK();
863 if (!mStream) return NO_INIT;
Mikhail Naganovddc91b42023-04-14 14:35:30 -0700864 return statusTFromBinderStatus(mStream->setHwGain({gain}));
Mikhail Naganov31d46652023-01-10 18:29:25 +0000865}
866
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800867status_t StreamInHalAidl::read(void *buffer, size_t bytes, size_t *read) {
868 if (buffer == nullptr || read == nullptr) {
869 return BAD_VALUE;
870 }
871 return transfer(buffer, bytes, read);
872}
873
874status_t StreamInHalAidl::getInputFramesLost(uint32_t *framesLost) {
875 if (framesLost == nullptr) {
876 return BAD_VALUE;
877 }
878 int32_t aidlXruns = 0;
Mikhail Naganove2084702023-09-28 14:37:12 -0700879 RETURN_STATUS_IF_ERROR(getXruns(&aidlXruns));
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800880 *framesLost = std::max<int32_t>(0, aidlXruns);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000881 return OK;
882}
883
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800884status_t StreamInHalAidl::getCapturePosition(int64_t *frames, int64_t *time) {
885 if (frames == nullptr || time == nullptr) {
886 return BAD_VALUE;
887 }
888 return getObservablePosition(frames, time);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000889}
890
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800891status_t StreamInHalAidl::getActiveMicrophones(std::vector<media::MicrophoneInfoFw> *microphones) {
892 if (!microphones) {
893 return BAD_VALUE;
894 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800895 TIME_CHECK();
896 if (!mStream) return NO_INIT;
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800897 sp<MicrophoneInfoProvider> micInfoProvider = mMicInfoProvider.promote();
898 if (!micInfoProvider) return NO_INIT;
899 auto staticInfo = micInfoProvider->getMicrophoneInfo();
900 if (!staticInfo) return INVALID_OPERATION;
901 std::vector<MicrophoneDynamicInfo> dynamicInfo;
902 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mStream->getActiveMicrophones(&dynamicInfo)));
903 std::vector<media::MicrophoneInfoFw> result;
904 result.reserve(dynamicInfo.size());
905 for (const auto& d : dynamicInfo) {
906 const auto staticInfoIt = std::find_if(staticInfo->begin(), staticInfo->end(),
907 [&](const auto& s) { return s.id == d.id; });
908 if (staticInfoIt != staticInfo->end()) {
909 // Convert into the c++ backend type from the ndk backend type via the legacy structure.
910 audio_microphone_characteristic_t legacy = VALUE_OR_RETURN_STATUS(
911 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t(
912 *staticInfoIt, d));
913 media::MicrophoneInfoFw info = VALUE_OR_RETURN_STATUS(
914 ::android::legacy2aidl_audio_microphone_characteristic_t_MicrophoneInfoFw(
915 legacy));
916 // Note: info.portId is not filled because it's a bit of framework info.
917 result.push_back(std::move(info));
918 } else {
919 ALOGE("%s: no static info for active microphone with id '%s'", __func__, d.id.c_str());
920 }
921 }
922 *microphones = std::move(result);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800923 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000924}
925
926status_t StreamInHalAidl::updateSinkMetadata(
Mikhail Naganovb6e57752023-03-08 18:12:47 -0800927 const StreamInHalInterface::SinkMetadata& sinkMetadata) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800928 TIME_CHECK();
929 if (!mStream) return NO_INIT;
Mikhail Naganovb6e57752023-03-08 18:12:47 -0800930 ::aidl::android::hardware::audio::common::SinkMetadata aidlMetadata =
931 VALUE_OR_RETURN_STATUS(legacy2aidl_SinkMetadata(sinkMetadata));
932 return statusTFromBinderStatus(mStream->updateMetadata(aidlMetadata));
Mikhail Naganov31d46652023-01-10 18:29:25 +0000933}
934
Mikhail Naganovddc91b42023-04-14 14:35:30 -0700935status_t StreamInHalAidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800936 TIME_CHECK();
937 if (!mStream) return NO_INIT;
Mikhail Naganovddc91b42023-04-14 14:35:30 -0700938 ::aidl::android::hardware::audio::core::IStreamIn::MicrophoneDirection aidlDirection =
939 VALUE_OR_RETURN_STATUS(
940 ::aidl::android::legacy2aidl_audio_microphone_direction_t_MicrophoneDirection(
941 direction));
942 return statusTFromBinderStatus(mStream->setMicrophoneDirection(aidlDirection));
Mikhail Naganov31d46652023-01-10 18:29:25 +0000943}
944
Mikhail Naganovddc91b42023-04-14 14:35:30 -0700945status_t StreamInHalAidl::setPreferredMicrophoneFieldDimension(float zoom) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800946 TIME_CHECK();
947 if (!mStream) return NO_INIT;
Mikhail Naganovddc91b42023-04-14 14:35:30 -0700948 return statusTFromBinderStatus(mStream->setMicrophoneFieldDimension(zoom));
Mikhail Naganov31d46652023-01-10 18:29:25 +0000949}
950
951} // namespace android