blob: cbc1578891f483b1c3dc6c2e71fc755821a3b3f7 [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>
David Lia0ad9f02023-03-02 21:46:19 +080025#include <media/AidlConversionCppNdk.h>
Mikhail Naganovb6e57752023-03-08 18:12:47 -080026#include <media/AidlConversionNdk.h>
David Lia6fb5752023-02-23 15:32:47 +000027#include <media/AidlConversionUtil.h>
David Lia0ad9f02023-03-02 21:46:19 +080028#include <media/AudioParameter.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000029#include <mediautils/TimeCheck.h>
David Lia0ad9f02023-03-02 21:46:19 +080030#include <system/audio.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000031#include <utils/Log.h>
32
33#include "DeviceHalAidl.h"
34#include "StreamHalAidl.h"
35
David Lia6fb5752023-02-23 15:32:47 +000036using ::aidl::android::aidl_utils::statusTFromBinderStatus;
Mikhail Naganovb6e57752023-03-08 18:12:47 -080037using ::aidl::android::hardware::audio::common::PlaybackTrackMetadata;
38using ::aidl::android::hardware::audio::common::RecordTrackMetadata;
Mikhail Naganov31d46652023-01-10 18:29:25 +000039using ::aidl::android::hardware::audio::core::IStreamCommon;
40using ::aidl::android::hardware::audio::core::IStreamIn;
41using ::aidl::android::hardware::audio::core::IStreamOut;
42using ::aidl::android::hardware::audio::core::StreamDescriptor;
Mikhail Naganovcad0afe2023-03-10 14:25:57 -080043using ::aidl::android::media::audio::common::MicrophoneDynamicInfo;
Mikhail Naganov31d46652023-01-10 18:29:25 +000044
45namespace android {
46
Mikhail Naganov89a9f742023-01-30 12:33:18 -080047using HalCommand = StreamDescriptor::Command;
48namespace {
49template<HalCommand::Tag cmd> HalCommand makeHalCommand() {
50 return HalCommand::make<cmd>(::aidl::android::media::audio::common::Void{});
51}
52template<HalCommand::Tag cmd, typename T> HalCommand makeHalCommand(T data) {
53 return HalCommand::make<cmd>(data);
54}
55} // namespace
56
Mikhail Naganovfab697c2023-01-11 19:33:13 +000057// static
58template<class T>
59std::shared_ptr<IStreamCommon> StreamHalAidl::getStreamCommon(const std::shared_ptr<T>& stream) {
60 std::shared_ptr<::aidl::android::hardware::audio::core::IStreamCommon> streamCommon;
61 if (stream != nullptr) {
62 if (ndk::ScopedAStatus status = stream->getStreamCommon(&streamCommon);
63 !status.isOk()) {
64 ALOGE("%s: failed to retrieve IStreamCommon instance: %s", __func__,
65 status.getDescription().c_str());
66 }
67 }
68 return streamCommon;
69}
70
Mikhail Naganov31d46652023-01-10 18:29:25 +000071StreamHalAidl::StreamHalAidl(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080072 std::string_view className, bool isInput, const audio_config& config,
Mikhail Naganov89a9f742023-01-30 12:33:18 -080073 int32_t nominalLatency, StreamContextAidl&& context,
74 const std::shared_ptr<IStreamCommon>& stream)
Mikhail Naganov31d46652023-01-10 18:29:25 +000075 : ConversionHelperAidl(className),
76 mIsInput(isInput),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080077 mConfig(configToBase(config)),
Mikhail Naganov89a9f742023-01-30 12:33:18 -080078 mContext(std::move(context)),
Mikhail Naganov31d46652023-01-10 18:29:25 +000079 mStream(stream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -080080 {
81 std::lock_guard l(mLock);
82 mLastReply.latencyMs = nominalLatency;
83 }
Mikhail Naganov31d46652023-01-10 18:29:25 +000084 // Instrument audio signal power logging.
85 // Note: This assumes channel mask, format, and sample rate do not change after creation.
86 if (audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
87 /* mStreamPowerLog.isUserDebugOrEngBuild() && */
88 StreamHalAidl::getAudioProperties(&config) == NO_ERROR) {
89 mStreamPowerLog.init(config.sample_rate, config.channel_mask, config.format);
90 }
91}
92
93StreamHalAidl::~StreamHalAidl() {
94 if (mStream != nullptr) {
95 ndk::ScopedAStatus status = mStream->close();
96 ALOGE_IF(!status.isOk(), "%s: status %s", __func__, status.getDescription().c_str());
97 }
98}
99
100status_t StreamHalAidl::getBufferSize(size_t *size) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800101 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000102 if (size == nullptr) {
103 return BAD_VALUE;
104 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800105 if (mContext.getFrameSizeBytes() == 0 || mContext.getBufferSizeFrames() == 0 ||
106 !mStream) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000107 return NO_INIT;
108 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800109 *size = mContext.getBufferSizeBytes();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000110 return OK;
111}
112
113status_t StreamHalAidl::getAudioProperties(audio_config_base_t *configBase) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800114 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000115 if (configBase == nullptr) {
116 return BAD_VALUE;
117 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800118 if (!mStream) return NO_INIT;
119 *configBase = mConfig;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000120 return OK;
121}
122
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700123namespace {
124
125// 'action' must accept a value of type 'T' and return 'status_t'.
126// The function returns 'true' if the parameter was found, and the action has succeeded.
127// The function returns 'false' if the parameter was not found.
128// Any errors get propagated, if there are errors it means the parameter was found.
129template<typename T, typename F>
130error::Result<bool> filterOutAndProcessParameter(
131 AudioParameter& parameters, const String8& key, const F& action) {
132 if (parameters.containsKey(key)) {
133 T value;
134 status_t status = parameters.get(key, value);
135 if (status == OK) {
136 parameters.remove(key);
137 status = action(value);
138 if (status == OK) return true;
139 }
140 return base::unexpected(status);
141 }
142 return false;
143}
144
145} // namespace
146
147status_t StreamHalAidl::setParameters(const String8& kvPairs) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000148 TIME_CHECK();
149 if (!mStream) return NO_INIT;
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700150
151 AudioParameter parameters(kvPairs);
152 ALOGD("%s: parameters: %s", __func__, parameters.toString().c_str());
153
154 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
155 parameters, String8(AudioParameter::keyStreamHwAvSync),
156 [&](int hwAvSyncId) {
157 return statusTFromBinderStatus(mStream->updateHwAvSyncId(hwAvSyncId));
158 }));
159
160 ALOGW_IF(parameters.size() != 0, "%s: unknown parameters, ignored: %s",
161 __func__, parameters.toString().c_str());
Mikhail Naganov31d46652023-01-10 18:29:25 +0000162 return OK;
163}
164
165status_t StreamHalAidl::getParameters(const String8& keys __unused, String8 *values) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800166 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000167 TIME_CHECK();
168 values->clear();
169 if (!mStream) return NO_INIT;
170 ALOGE("%s not implemented yet", __func__);
171 return OK;
172}
173
174status_t StreamHalAidl::getFrameSize(size_t *size) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800175 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000176 if (size == nullptr) {
177 return BAD_VALUE;
178 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800179 if (mContext.getFrameSizeBytes() == 0 || !mStream) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000180 return NO_INIT;
181 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800182 *size = mContext.getFrameSizeBytes();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000183 return OK;
184}
185
186status_t StreamHalAidl::addEffect(sp<EffectHalInterface> effect __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800187 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000188 TIME_CHECK();
189 if (!mStream) return NO_INIT;
190 ALOGE("%s not implemented yet", __func__);
191 return OK;
192}
193
194status_t StreamHalAidl::removeEffect(sp<EffectHalInterface> effect __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800195 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000196 TIME_CHECK();
197 if (!mStream) return NO_INIT;
198 ALOGE("%s not implemented yet", __func__);
199 return OK;
200}
201
202status_t StreamHalAidl::standby() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800203 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000204 TIME_CHECK();
205 if (!mStream) return NO_INIT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800206 const auto state = getState();
207 StreamDescriptor::Reply reply;
208 switch (state) {
209 case StreamDescriptor::State::ACTIVE:
210 if (status_t status = pause(&reply); status != OK) return status;
211 if (reply.state != StreamDescriptor::State::PAUSED) {
212 ALOGE("%s: unexpected stream state: %s (expected PAUSED)",
213 __func__, toString(reply.state).c_str());
214 return INVALID_OPERATION;
215 }
216 FALLTHROUGH_INTENDED;
217 case StreamDescriptor::State::PAUSED:
218 case StreamDescriptor::State::DRAIN_PAUSED:
Jasmine Cha105c66f2023-02-15 16:29:36 +0800219 if (mIsInput) return flush();
220 if (status_t status = flush(&reply); status != OK) return status;
221 if (reply.state != StreamDescriptor::State::IDLE) {
222 ALOGE("%s: unexpected stream state: %s (expected IDLE)",
223 __func__, toString(reply.state).c_str());
224 return INVALID_OPERATION;
225 }
226 FALLTHROUGH_INTENDED;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800227 case StreamDescriptor::State::IDLE:
228 if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::standby>(),
Jasmine Cha105c66f2023-02-15 16:29:36 +0800229 &reply, true /*safeFromNonWorkerThread*/); status != OK) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800230 return status;
231 }
232 if (reply.state != StreamDescriptor::State::STANDBY) {
233 ALOGE("%s: unexpected stream state: %s (expected STANDBY)",
234 __func__, toString(reply.state).c_str());
235 return INVALID_OPERATION;
236 }
237 FALLTHROUGH_INTENDED;
238 case StreamDescriptor::State::STANDBY:
239 return OK;
240 default:
241 ALOGE("%s: not supported from %s stream state %s",
242 __func__, mIsInput ? "input" : "output", toString(state).c_str());
243 return INVALID_OPERATION;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800244 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000245}
246
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000247status_t StreamHalAidl::dump(int fd, const Vector<String16>& args) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800248 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000249 TIME_CHECK();
250 if (!mStream) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000251 return mStream->dump(fd, Args(args).args(), args.size());
Mikhail Naganov31d46652023-01-10 18:29:25 +0000252}
253
254status_t StreamHalAidl::start() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800255 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000256 TIME_CHECK();
257 if (!mStream) return NO_INIT;
258 ALOGE("%s not implemented yet", __func__);
259 return OK;
260}
261
262status_t StreamHalAidl::stop() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800263 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
264 TIME_CHECK();
265 if (!mStream) return NO_INIT;
266 ALOGE("%s not implemented yet", __func__);
267 return OK;
268}
269
270status_t StreamHalAidl::getLatency(uint32_t *latency) {
271 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
272 if (!mStream) return NO_INIT;
273 StreamDescriptor::Reply reply;
274 if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
275 return status;
276 }
277 *latency = std::max<int32_t>(0, reply.latencyMs);
278 return OK;
279}
280
281status_t StreamHalAidl::getObservablePosition(int64_t *frames, int64_t *timestamp) {
282 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
283 if (!mStream) return NO_INIT;
284 StreamDescriptor::Reply reply;
285 if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
286 return status;
287 }
288 *frames = reply.observable.frames;
289 *timestamp = reply.observable.timeNs;
290 return OK;
291}
292
293status_t StreamHalAidl::getXruns(int32_t *frames) {
294 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
295 if (!mStream) return NO_INIT;
296 StreamDescriptor::Reply reply;
297 if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
298 return status;
299 }
300 *frames = reply.xrunFrames;
301 return OK;
302}
303
304status_t StreamHalAidl::transfer(void *buffer, size_t bytes, size_t *transferred) {
305 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
Shunkai Yaoc6308712023-02-22 17:53:04 +0000306 // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800307 if (!mStream || mContext.getDataMQ() == nullptr) return NO_INIT;
308 mWorkerTid.store(gettid(), std::memory_order_release);
309 // Switch the stream into an active state if needed.
310 // Note: in future we may add support for priming the audio pipeline
311 // with data prior to enabling output (thus we can issue a "burst" command in the "standby"
312 // stream state), however this scenario wasn't supported by the HIDL HAL.
313 if (getState() == StreamDescriptor::State::STANDBY) {
314 StreamDescriptor::Reply reply;
315 if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply);
316 status != OK) {
317 return status;
318 }
319 if (reply.state != StreamDescriptor::State::IDLE) {
320 ALOGE("%s: failed to get the stream out of standby, actual state: %s",
321 __func__, toString(reply.state).c_str());
322 return INVALID_OPERATION;
323 }
324 }
325 if (!mIsInput) {
326 bytes = std::min(bytes, mContext.getDataMQ()->availableToWrite());
327 }
328 StreamDescriptor::Command burst =
329 StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(bytes);
330 if (!mIsInput) {
331 if (!mContext.getDataMQ()->write(static_cast<const int8_t*>(buffer), bytes)) {
332 ALOGE("%s: failed to write %zu bytes to data MQ", __func__, bytes);
333 return NOT_ENOUGH_DATA;
334 }
335 }
336 StreamDescriptor::Reply reply;
337 if (status_t status = sendCommand(burst, &reply); status != OK) {
338 return status;
339 }
Jasmine Chaad99fb02023-02-10 12:52:58 +0800340 *transferred = reply.fmqByteCount;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800341 if (mIsInput) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800342 LOG_ALWAYS_FATAL_IF(*transferred > bytes,
343 "%s: HAL module read %zu bytes, which exceeds requested count %zu",
344 __func__, *transferred, bytes);
Jasmine Cha105c66f2023-02-15 16:29:36 +0800345 if (auto toRead = mContext.getDataMQ()->availableToRead();
346 toRead != 0 && !mContext.getDataMQ()->read(static_cast<int8_t*>(buffer), toRead)) {
347 ALOGE("%s: failed to read %zu bytes to data MQ", __func__, toRead);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800348 return NOT_ENOUGH_DATA;
349 }
350 }
351 mStreamPowerLog.log(buffer, *transferred);
352 return OK;
353}
354
355status_t StreamHalAidl::pause(StreamDescriptor::Reply* reply) {
356 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
357 TIME_CHECK();
358 if (!mStream) return NO_INIT;
359 return sendCommand(makeHalCommand<HalCommand::Tag::pause>(), reply,
360 true /*safeFromNonWorkerThread*/); // The workers stops its I/O activity first.
361}
362
363status_t StreamHalAidl::resume(StreamDescriptor::Reply* reply) {
364 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
365 TIME_CHECK();
366 if (!mStream) return NO_INIT;
367 if (mIsInput) {
368 return sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), reply);
369 } else {
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800370 if (mContext.isAsynchronous()) {
371 // Handle pause-flush-resume sequence. 'flush' from PAUSED goes to
372 // IDLE. We move here from IDLE to ACTIVE (same as 'start' from PAUSED).
373 const auto state = getState();
374 if (state == StreamDescriptor::State::IDLE) {
375 StreamDescriptor::Reply localReply{};
376 StreamDescriptor::Reply* innerReply = reply ?: &localReply;
377 if (status_t status =
378 sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), innerReply);
379 status != OK) {
380 return status;
381 }
382 if (innerReply->state != StreamDescriptor::State::ACTIVE) {
383 ALOGE("%s: unexpected stream state: %s (expected ACTIVE)",
384 __func__, toString(innerReply->state).c_str());
385 return INVALID_OPERATION;
386 }
387 return OK;
388 }
389 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800390 return sendCommand(makeHalCommand<HalCommand::Tag::start>(), reply);
391 }
392}
393
394status_t StreamHalAidl::drain(bool earlyNotify, StreamDescriptor::Reply* reply) {
395 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
396 TIME_CHECK();
397 if (!mStream) return NO_INIT;
398 return sendCommand(makeHalCommand<HalCommand::Tag::drain>(
399 mIsInput ? StreamDescriptor::DrainMode::DRAIN_UNSPECIFIED :
400 earlyNotify ? StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY :
David Lia6fb5752023-02-23 15:32:47 +0000401 StreamDescriptor::DrainMode::DRAIN_ALL), reply,
402 true /*safeFromNonWorkerThread*/);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800403}
404
405status_t StreamHalAidl::flush(StreamDescriptor::Reply* reply) {
406 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
407 TIME_CHECK();
408 if (!mStream) return NO_INIT;
409 return sendCommand(makeHalCommand<HalCommand::Tag::flush>(), reply,
410 true /*safeFromNonWorkerThread*/); // The workers stops its I/O activity first.
411}
412
413status_t StreamHalAidl::exit() {
414 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000415 TIME_CHECK();
416 if (!mStream) return NO_INIT;
417 ALOGE("%s not implemented yet", __func__);
418 return OK;
419}
420
421status_t StreamHalAidl::createMmapBuffer(int32_t minSizeFrames __unused,
422 struct audio_mmap_buffer_info *info __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800423 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000424 TIME_CHECK();
425 if (!mStream) return NO_INIT;
426 ALOGE("%s not implemented yet", __func__);
427 return OK;
428}
429
430status_t StreamHalAidl::getMmapPosition(struct audio_mmap_position *position __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800431 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000432 TIME_CHECK();
433 if (!mStream) return NO_INIT;
434 ALOGE("%s not implemented yet", __func__);
435 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
443status_t StreamHalAidl::getHalPid(pid_t *pid __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800444 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000445 TIME_CHECK();
446 if (!mStream) return NO_INIT;
447 ALOGE("%s not implemented yet", __func__);
448 return OK;
449}
450
451bool StreamHalAidl::requestHalThreadPriority(pid_t threadPid __unused, pid_t threadId __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800452 // Obsolete, must be done by the HAL module.
453 return true;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000454}
455
456status_t StreamHalAidl::legacyCreateAudioPatch(const struct audio_port_config& port __unused,
457 std::optional<audio_source_t> source __unused,
458 audio_devices_t type __unused) {
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000459 // Obsolete since 'DeviceHalAidl.supportsAudioPatches' always returns 'true'.
460 return INVALID_OPERATION;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000461}
462
463status_t StreamHalAidl::legacyReleaseAudioPatch() {
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000464 // Obsolete since 'DeviceHalAidl.supportsAudioPatches' always returns 'true'.
465 return INVALID_OPERATION;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000466}
467
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800468status_t StreamHalAidl::sendCommand(
469 const ::aidl::android::hardware::audio::core::StreamDescriptor::Command &command,
470 ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply,
471 bool safeFromNonWorkerThread) {
Shunkai Yaoc6308712023-02-22 17:53:04 +0000472 // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800473 if (!safeFromNonWorkerThread) {
474 const pid_t workerTid = mWorkerTid.load(std::memory_order_acquire);
475 LOG_ALWAYS_FATAL_IF(workerTid != gettid(),
476 "%s %s: must be invoked from the worker thread (%d)",
477 __func__, command.toString().c_str(), workerTid);
478 }
479 if (!mContext.getCommandMQ()->writeBlocking(&command, 1)) {
480 ALOGE("%s: failed to write command %s to MQ", __func__, command.toString().c_str());
481 return NOT_ENOUGH_DATA;
482 }
483 StreamDescriptor::Reply localReply{};
484 if (reply == nullptr) {
485 reply = &localReply;
486 }
487 if (!mContext.getReplyMQ()->readBlocking(reply, 1)) {
488 ALOGE("%s: failed to read from reply MQ, command %s", __func__, command.toString().c_str());
489 return NOT_ENOUGH_DATA;
490 }
491 {
492 std::lock_guard l(mLock);
493 mLastReply = *reply;
494 }
495 switch (reply->status) {
496 case STATUS_OK: return OK;
497 case STATUS_BAD_VALUE: return BAD_VALUE;
498 case STATUS_INVALID_OPERATION: return INVALID_OPERATION;
499 case STATUS_NOT_ENOUGH_DATA: return NOT_ENOUGH_DATA;
500 default:
501 ALOGE("%s: unexpected status %d returned for command %s",
502 __func__, reply->status, command.toString().c_str());
503 return INVALID_OPERATION;
504 }
505}
506
507status_t StreamHalAidl::updateCountersIfNeeded(
508 ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply) {
509 if (mWorkerTid.load(std::memory_order_acquire) == gettid()) {
510 if (const auto state = getState(); state != StreamDescriptor::State::ACTIVE &&
511 state != StreamDescriptor::State::DRAINING &&
512 state != StreamDescriptor::State::TRANSFERRING) {
513 return sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), reply);
514 }
515 }
516 if (reply != nullptr) {
517 std::lock_guard l(mLock);
518 *reply = mLastReply;
519 }
520 return OK;
521}
522
Mikhail Naganovb6e57752023-03-08 18:12:47 -0800523// static
Mikhail Naganov19418e32023-03-10 17:55:14 -0800524ConversionResult<::aidl::android::hardware::audio::common::SourceMetadata>
Mikhail Naganovb6e57752023-03-08 18:12:47 -0800525StreamOutHalAidl::legacy2aidl_SourceMetadata(const StreamOutHalInterface::SourceMetadata& legacy) {
526 ::aidl::android::hardware::audio::common::SourceMetadata aidl;
527 aidl.tracks = VALUE_OR_RETURN(
528 ::aidl::android::convertContainer<std::vector<PlaybackTrackMetadata>>(
529 legacy.tracks,
530 ::aidl::android::legacy2aidl_playback_track_metadata_v7_PlaybackTrackMetadata));
531 return aidl;
532}
533
Mikhail Naganov31d46652023-01-10 18:29:25 +0000534StreamOutHalAidl::StreamOutHalAidl(
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800535 const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800536 const std::shared_ptr<IStreamOut>& stream, const sp<CallbackBroker>& callbackBroker)
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800537 : StreamHalAidl("StreamOutHalAidl", false /*isInput*/, config, nominalLatency,
538 std::move(context), getStreamCommon(stream)),
David Lia0ad9f02023-03-02 21:46:19 +0800539 mStream(stream), mCallbackBroker(callbackBroker) {
540 // Initialize the offload metadata
541 mOffloadMetadata.sampleRate = static_cast<int32_t>(config.sample_rate);
542 mOffloadMetadata.channelMask = VALUE_OR_FATAL(
Mikhail Naganov893b7c22023-03-13 15:48:11 -0700543 ::aidl::android::legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
544 config.channel_mask, false));
David Lia0ad9f02023-03-02 21:46:19 +0800545 mOffloadMetadata.averageBitRatePerSecond = static_cast<int32_t>(config.offload_info.bit_rate);
546}
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800547
548StreamOutHalAidl::~StreamOutHalAidl() {
549 if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
550 broker->clearCallbacks(this);
551 }
552}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000553
David Lia0ad9f02023-03-02 21:46:19 +0800554status_t StreamOutHalAidl::setParameters(const String8& kvPairs) {
555 if (!mStream) return NO_INIT;
556
557 AudioParameter parameters(kvPairs);
558 ALOGD("%s parameters: %s", __func__, parameters.toString().c_str());
559
Mikhail Naganovb6e57752023-03-08 18:12:47 -0800560 if (status_t status = filterAndUpdateOffloadMetadata(parameters); status != OK) {
561 ALOGW("%s filtering or updating offload metadata failed: %d", __func__, status);
David Lia0ad9f02023-03-02 21:46:19 +0800562 }
563
564 return StreamHalAidl::setParameters(parameters.toString());
565}
566
Mikhail Naganov31d46652023-01-10 18:29:25 +0000567status_t StreamOutHalAidl::getLatency(uint32_t *latency) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800568 return StreamHalAidl::getLatency(latency);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000569}
570
David Lia6fb5752023-02-23 15:32:47 +0000571status_t StreamOutHalAidl::setVolume(float left, float right) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000572 TIME_CHECK();
573 if (!mStream) return NO_INIT;
David Lia6fb5752023-02-23 15:32:47 +0000574 return statusTFromBinderStatus(mStream->setHwVolume({left, right}));
Mikhail Naganov31d46652023-01-10 18:29:25 +0000575}
576
577status_t StreamOutHalAidl::selectPresentation(int presentationId __unused, int programId __unused) {
578 TIME_CHECK();
579 if (!mStream) return NO_INIT;
580 ALOGE("%s not implemented yet", __func__);
581 return OK;
582}
583
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800584status_t StreamOutHalAidl::write(const void *buffer, size_t bytes, size_t *written) {
585 if (buffer == nullptr || written == nullptr) {
586 return BAD_VALUE;
587 }
588 // For the output scenario, 'transfer' does not modify the buffer.
589 return transfer(const_cast<void*>(buffer), bytes, written);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000590}
591
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800592status_t StreamOutHalAidl::getRenderPosition(uint32_t *dspFrames) {
593 if (dspFrames == nullptr) {
594 return BAD_VALUE;
595 }
596 int64_t aidlFrames = 0, aidlTimestamp = 0;
597 if (status_t status = getObservablePosition(&aidlFrames, &aidlTimestamp); status != OK) {
598 return OK;
599 }
600 *dspFrames = std::clamp<int64_t>(aidlFrames, 0, UINT32_MAX);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000601 return OK;
602}
603
604status_t StreamOutHalAidl::getNextWriteTimestamp(int64_t *timestamp __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800605 // Obsolete, use getPresentationPosition.
606 return INVALID_OPERATION;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000607}
608
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800609status_t StreamOutHalAidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000610 TIME_CHECK();
611 if (!mStream) return NO_INIT;
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800612 if (!mContext.isAsynchronous()) {
613 ALOGE("%s: the callback is intended for asynchronous streams only", __func__);
614 return INVALID_OPERATION;
615 }
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800616 if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
617 if (auto cb = callback.promote(); cb != nullptr) {
618 broker->setStreamOutCallback(this, cb);
619 } else {
620 // It is expected that the framework never passes a null pointer.
621 // In the AIDL model callbacks can't be "unregistered".
622 LOG_ALWAYS_FATAL("%s: received an expired or null callback pointer", __func__);
623 }
624 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000625 return OK;
626}
627
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800628status_t StreamOutHalAidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
629 if (supportsPause == nullptr || supportsResume == nullptr) {
630 return BAD_VALUE;
631 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000632 TIME_CHECK();
633 if (!mStream) return NO_INIT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800634 *supportsPause = *supportsResume = true;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000635 return OK;
636}
637
638status_t StreamOutHalAidl::pause() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800639 return StreamHalAidl::pause();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000640}
641
642status_t StreamOutHalAidl::resume() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800643 return StreamHalAidl::resume();
644}
645
646status_t StreamOutHalAidl::supportsDrain(bool *supportsDrain) {
647 if (supportsDrain == nullptr) {
648 return BAD_VALUE;
649 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000650 TIME_CHECK();
651 if (!mStream) return NO_INIT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800652 *supportsDrain = true;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000653 return OK;
654}
655
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800656status_t StreamOutHalAidl::drain(bool earlyNotify) {
657 return StreamHalAidl::drain(earlyNotify);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000658}
659
660status_t StreamOutHalAidl::flush() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800661 return StreamHalAidl::flush();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000662}
663
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800664status_t StreamOutHalAidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
665 if (frames == nullptr || timestamp == nullptr) {
666 return BAD_VALUE;
667 }
668 int64_t aidlFrames = 0, aidlTimestamp = 0;
669 if (status_t status = getObservablePosition(&aidlFrames, &aidlTimestamp); status != OK) {
670 return status;
671 }
672 *frames = std::max<int64_t>(0, aidlFrames);
673 timestamp->tv_sec = aidlTimestamp / NANOS_PER_SECOND;
674 timestamp->tv_nsec = aidlTimestamp - timestamp->tv_sec * NANOS_PER_SECOND;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000675 return OK;
676}
677
678status_t StreamOutHalAidl::updateSourceMetadata(
Mikhail Naganovb6e57752023-03-08 18:12:47 -0800679 const StreamOutHalInterface::SourceMetadata& sourceMetadata) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000680 TIME_CHECK();
681 if (!mStream) return NO_INIT;
Mikhail Naganovb6e57752023-03-08 18:12:47 -0800682 ::aidl::android::hardware::audio::common::SourceMetadata aidlMetadata =
683 VALUE_OR_RETURN_STATUS(legacy2aidl_SourceMetadata(sourceMetadata));
684 return statusTFromBinderStatus(mStream->updateMetadata(aidlMetadata));
Mikhail Naganov31d46652023-01-10 18:29:25 +0000685}
686
687status_t StreamOutHalAidl::getDualMonoMode(audio_dual_mono_mode_t* mode __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800688 TIME_CHECK();
689 if (!mStream) return NO_INIT;
690 ALOGE("%s not implemented yet", __func__);
691 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000692}
693
694status_t StreamOutHalAidl::setDualMonoMode(audio_dual_mono_mode_t mode __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800695 TIME_CHECK();
696 if (!mStream) return NO_INIT;
697 ALOGE("%s not implemented yet", __func__);
698 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000699}
700
701status_t StreamOutHalAidl::getAudioDescriptionMixLevel(float* leveldB __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800702 TIME_CHECK();
703 if (!mStream) return NO_INIT;
704 ALOGE("%s not implemented yet", __func__);
705 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000706}
707
708status_t StreamOutHalAidl::setAudioDescriptionMixLevel(float leveldB __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800709 TIME_CHECK();
710 if (!mStream) return NO_INIT;
711 ALOGE("%s not implemented yet", __func__);
712 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000713}
714
715status_t StreamOutHalAidl::getPlaybackRateParameters(
716 audio_playback_rate_t* playbackRate __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800717 TIME_CHECK();
718 if (!mStream) return NO_INIT;
719 ALOGE("%s not implemented yet", __func__);
David Lia6fb5752023-02-23 15:32:47 +0000720 return BAD_VALUE;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000721}
722
723status_t StreamOutHalAidl::setPlaybackRateParameters(
724 const audio_playback_rate_t& playbackRate __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800725 TIME_CHECK();
726 if (!mStream) return NO_INIT;
727 ALOGE("%s not implemented yet", __func__);
David Lia6fb5752023-02-23 15:32:47 +0000728 return BAD_VALUE;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000729}
730
731status_t StreamOutHalAidl::setEventCallback(
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800732 const sp<StreamOutHalInterfaceEventCallback>& callback) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800733 TIME_CHECK();
734 if (!mStream) return NO_INIT;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800735 if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
736 broker->setStreamOutEventCallback(this, callback);
737 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800738 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000739}
740
Mikhail Naganov31d46652023-01-10 18:29:25 +0000741status_t StreamOutHalAidl::setLatencyMode(audio_latency_mode_t mode __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800742 TIME_CHECK();
743 if (!mStream) return NO_INIT;
744 ALOGE("%s not implemented yet", __func__);
745 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000746};
747
748status_t StreamOutHalAidl::getRecommendedLatencyModes(
749 std::vector<audio_latency_mode_t> *modes __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800750 TIME_CHECK();
751 if (!mStream) return NO_INIT;
752 ALOGE("%s not implemented yet", __func__);
753 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000754};
755
756status_t StreamOutHalAidl::setLatencyModeCallback(
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800757 const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800758 TIME_CHECK();
759 if (!mStream) return NO_INIT;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800760 if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
761 broker->setStreamOutLatencyModeCallback(this, callback);
762 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800763 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000764};
765
Mikhail Naganov31d46652023-01-10 18:29:25 +0000766status_t StreamOutHalAidl::exit() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800767 return StreamHalAidl::exit();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000768}
769
David Lia0ad9f02023-03-02 21:46:19 +0800770status_t StreamOutHalAidl::filterAndUpdateOffloadMetadata(AudioParameter &parameters) {
771 TIME_CHECK();
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700772 bool updateMetadata = false;
773 if (VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
774 parameters, String8(AudioParameter::keyOffloadCodecAverageBitRate),
775 [&](int value) {
776 return value > 0 ?
777 mOffloadMetadata.averageBitRatePerSecond = value, OK : BAD_VALUE;
778 }))) {
779 updateMetadata = true;
780 }
781 if (VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
782 parameters, String8(AudioParameter::keyOffloadCodecSampleRate),
783 [&](int value) {
784 return value > 0 ? mOffloadMetadata.sampleRate = value, OK : BAD_VALUE;
785 }))) {
786 updateMetadata = true;
787 }
788 if (VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
789 parameters, String8(AudioParameter::keyOffloadCodecChannels),
790 [&](int value) -> status_t {
791 if (value > 0) {
792 audio_channel_mask_t channel_mask = audio_channel_out_mask_from_count(
793 static_cast<uint32_t>(value));
794 if (channel_mask == AUDIO_CHANNEL_INVALID) return BAD_VALUE;
795 mOffloadMetadata.channelMask = VALUE_OR_RETURN_STATUS(
796 ::aidl::android::legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
797 channel_mask, false /*isInput*/));
798 }
799 return BAD_VALUE;
800 }))) {
801 updateMetadata = true;
802 }
803 if (VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
804 parameters, String8(AudioParameter::keyOffloadCodecDelaySamples),
805 [&](int value) {
806 // The legacy keys are misnamed, the value is in frames.
807 return value > 0 ? mOffloadMetadata.delayFrames = value, OK : BAD_VALUE;
808 }))) {
809 updateMetadata = true;
810 }
811 if (VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
812 parameters, String8(AudioParameter::keyOffloadCodecPaddingSamples),
813 [&](int value) {
814 // The legacy keys are misnamed, the value is in frames.
815 return value > 0 ? mOffloadMetadata.paddingFrames = value, OK : BAD_VALUE;
816 }))) {
817 updateMetadata = true;
818 }
819 if (updateMetadata) {
David Lia0ad9f02023-03-02 21:46:19 +0800820 ALOGD("%s set offload metadata %s", __func__, mOffloadMetadata.toString().c_str());
Mikhail Naganov08a62ab2023-03-14 17:11:51 -0700821 if (status_t status = statusTFromBinderStatus(
822 mStream->updateOffloadMetadata(mOffloadMetadata)); status != OK) {
David Lia0ad9f02023-03-02 21:46:19 +0800823 ALOGE("%s: updateOffloadMetadata failed %d", __func__, status);
824 return status;
825 }
826 }
827 return OK;
828}
829
Mikhail Naganovb6e57752023-03-08 18:12:47 -0800830// static
Mikhail Naganov19418e32023-03-10 17:55:14 -0800831ConversionResult<::aidl::android::hardware::audio::common::SinkMetadata>
Mikhail Naganovb6e57752023-03-08 18:12:47 -0800832StreamInHalAidl::legacy2aidl_SinkMetadata(const StreamInHalInterface::SinkMetadata& legacy) {
833 ::aidl::android::hardware::audio::common::SinkMetadata aidl;
834 aidl.tracks = VALUE_OR_RETURN(
835 ::aidl::android::convertContainer<std::vector<RecordTrackMetadata>>(
836 legacy.tracks,
837 ::aidl::android::legacy2aidl_record_track_metadata_v7_RecordTrackMetadata));
838 return aidl;
839}
840
Mikhail Naganov31d46652023-01-10 18:29:25 +0000841StreamInHalAidl::StreamInHalAidl(
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800842 const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800843 const std::shared_ptr<IStreamIn>& stream, const sp<MicrophoneInfoProvider>& micInfoProvider)
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800844 : StreamHalAidl("StreamInHalAidl", true /*isInput*/, config, nominalLatency,
845 std::move(context), getStreamCommon(stream)),
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800846 mStream(stream), mMicInfoProvider(micInfoProvider) {}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000847
848status_t StreamInHalAidl::setGain(float gain __unused) {
849 TIME_CHECK();
850 if (!mStream) return NO_INIT;
851 ALOGE("%s not implemented yet", __func__);
852 return OK;
853}
854
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800855status_t StreamInHalAidl::read(void *buffer, size_t bytes, size_t *read) {
856 if (buffer == nullptr || read == nullptr) {
857 return BAD_VALUE;
858 }
859 return transfer(buffer, bytes, read);
860}
861
862status_t StreamInHalAidl::getInputFramesLost(uint32_t *framesLost) {
863 if (framesLost == nullptr) {
864 return BAD_VALUE;
865 }
866 int32_t aidlXruns = 0;
867 if (status_t status = getXruns(&aidlXruns); status != OK) {
868 return status;
869 }
870 *framesLost = std::max<int32_t>(0, aidlXruns);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000871 return OK;
872}
873
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800874status_t StreamInHalAidl::getCapturePosition(int64_t *frames, int64_t *time) {
875 if (frames == nullptr || time == nullptr) {
876 return BAD_VALUE;
877 }
878 return getObservablePosition(frames, time);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000879}
880
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800881status_t StreamInHalAidl::getActiveMicrophones(std::vector<media::MicrophoneInfoFw> *microphones) {
882 if (!microphones) {
883 return BAD_VALUE;
884 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800885 TIME_CHECK();
886 if (!mStream) return NO_INIT;
Mikhail Naganovcad0afe2023-03-10 14:25:57 -0800887 sp<MicrophoneInfoProvider> micInfoProvider = mMicInfoProvider.promote();
888 if (!micInfoProvider) return NO_INIT;
889 auto staticInfo = micInfoProvider->getMicrophoneInfo();
890 if (!staticInfo) return INVALID_OPERATION;
891 std::vector<MicrophoneDynamicInfo> dynamicInfo;
892 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mStream->getActiveMicrophones(&dynamicInfo)));
893 std::vector<media::MicrophoneInfoFw> result;
894 result.reserve(dynamicInfo.size());
895 for (const auto& d : dynamicInfo) {
896 const auto staticInfoIt = std::find_if(staticInfo->begin(), staticInfo->end(),
897 [&](const auto& s) { return s.id == d.id; });
898 if (staticInfoIt != staticInfo->end()) {
899 // Convert into the c++ backend type from the ndk backend type via the legacy structure.
900 audio_microphone_characteristic_t legacy = VALUE_OR_RETURN_STATUS(
901 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t(
902 *staticInfoIt, d));
903 media::MicrophoneInfoFw info = VALUE_OR_RETURN_STATUS(
904 ::android::legacy2aidl_audio_microphone_characteristic_t_MicrophoneInfoFw(
905 legacy));
906 // Note: info.portId is not filled because it's a bit of framework info.
907 result.push_back(std::move(info));
908 } else {
909 ALOGE("%s: no static info for active microphone with id '%s'", __func__, d.id.c_str());
910 }
911 }
912 *microphones = std::move(result);
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800913 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000914}
915
916status_t StreamInHalAidl::updateSinkMetadata(
Mikhail Naganovb6e57752023-03-08 18:12:47 -0800917 const StreamInHalInterface::SinkMetadata& sinkMetadata) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800918 TIME_CHECK();
919 if (!mStream) return NO_INIT;
Mikhail Naganovb6e57752023-03-08 18:12:47 -0800920 ::aidl::android::hardware::audio::common::SinkMetadata aidlMetadata =
921 VALUE_OR_RETURN_STATUS(legacy2aidl_SinkMetadata(sinkMetadata));
922 return statusTFromBinderStatus(mStream->updateMetadata(aidlMetadata));
Mikhail Naganov31d46652023-01-10 18:29:25 +0000923}
924
925status_t StreamInHalAidl::setPreferredMicrophoneDirection(
926 audio_microphone_direction_t direction __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800927 TIME_CHECK();
928 if (!mStream) return NO_INIT;
929 ALOGE("%s not implemented yet", __func__);
930 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000931}
932
933status_t StreamInHalAidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800934 TIME_CHECK();
935 if (!mStream) return NO_INIT;
936 ALOGE("%s not implemented yet", __func__);
937 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000938}
939
940} // namespace android