1 /*
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
20 #include <algorithm>
21 #include <cstdint>
22
23 #include <audio_utils/clock.h>
24 #include <media/AidlConversion.h>
25 #include <media/AidlConversionCore.h>
26 #include <media/AidlConversionCppNdk.h>
27 #include <media/AidlConversionNdk.h>
28 #include <media/AidlConversionUtil.h>
29 #include <media/AudioParameter.h>
30 #include <mediautils/TimeCheck.h>
31 #include <system/audio.h>
32 #include <Utils.h>
33 #include <utils/Log.h>
34
35 #include "DeviceHalAidl.h"
36 #include "EffectHalAidl.h"
37 #include "StreamHalAidl.h"
38
39 using ::aidl::android::aidl_utils::statusTFromBinderStatus;
40 using ::aidl::android::hardware::audio::common::kDumpFromAudioServerArgument;
41 using ::aidl::android::hardware::audio::common::PlaybackTrackMetadata;
42 using ::aidl::android::hardware::audio::common::RecordTrackMetadata;
43 using ::aidl::android::hardware::audio::core::IStreamCommon;
44 using ::aidl::android::hardware::audio::core::IStreamIn;
45 using ::aidl::android::hardware::audio::core::IStreamOut;
46 using ::aidl::android::hardware::audio::core::MmapBufferDescriptor;
47 using ::aidl::android::hardware::audio::core::StreamDescriptor;
48 using ::aidl::android::media::audio::common::MicrophoneDynamicInfo;
49 using ::aidl::android::media::audio::IHalAdapterVendorExtension;
50
51 namespace android {
52
53 using HalCommand = StreamDescriptor::Command;
54 namespace {
makeHalCommand()55 template<HalCommand::Tag cmd> HalCommand makeHalCommand() {
56 return HalCommand::make<cmd>(::aidl::android::media::audio::common::Void{});
57 }
makeHalCommand(T data)58 template<HalCommand::Tag cmd, typename T> HalCommand makeHalCommand(T data) {
59 return HalCommand::make<cmd>(data);
60 }
61 } // namespace
62
63 // static
64 template<class T>
getStreamCommon(const std::shared_ptr<T> & stream)65 std::shared_ptr<IStreamCommon> StreamHalAidl::getStreamCommon(const std::shared_ptr<T>& stream) {
66 std::shared_ptr<::aidl::android::hardware::audio::core::IStreamCommon> streamCommon;
67 if (stream != nullptr) {
68 if (ndk::ScopedAStatus status = stream->getStreamCommon(&streamCommon);
69 !status.isOk()) {
70 ALOGE("%s: failed to retrieve IStreamCommon instance: %s", __func__,
71 status.getDescription().c_str());
72 }
73 }
74 return streamCommon;
75 }
76
StreamHalAidl(std::string_view className,bool isInput,const audio_config & config,int32_t nominalLatency,StreamContextAidl && context,const std::shared_ptr<IStreamCommon> & stream,const std::shared_ptr<IHalAdapterVendorExtension> & vext)77 StreamHalAidl::StreamHalAidl(
78 std::string_view className, bool isInput, const audio_config& config,
79 int32_t nominalLatency, StreamContextAidl&& context,
80 const std::shared_ptr<IStreamCommon>& stream,
81 const std::shared_ptr<IHalAdapterVendorExtension>& vext)
82 : ConversionHelperAidl(className),
83 mIsInput(isInput),
84 mConfig(configToBase(config)),
85 mContext(std::move(context)),
86 mStream(stream),
87 mVendorExt(vext),
88 mLastReplyLifeTimeNs(
89 std::min(static_cast<size_t>(100),
90 2 * mContext.getBufferDurationMs(mConfig.sample_rate))
91 * NANOS_PER_MILLISECOND)
92 {
93 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
94 {
95 std::lock_guard l(mLock);
96 mLastReply.latencyMs = nominalLatency;
97 }
98 // Instrument audio signal power logging.
99 // Note: This assumes channel mask, format, and sample rate do not change after creation.
100 if (audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
101 /* mStreamPowerLog.isUserDebugOrEngBuild() && */
102 StreamHalAidl::getAudioProperties(&config) == NO_ERROR) {
103 mStreamPowerLog.init(config.sample_rate, config.channel_mask, config.format);
104 }
105 }
106
~StreamHalAidl()107 StreamHalAidl::~StreamHalAidl() {
108 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
109 if (mStream != nullptr) {
110 ndk::ScopedAStatus status = mStream->close();
111 ALOGE_IF(!status.isOk(), "%s: status %s", __func__, status.getDescription().c_str());
112 }
113 }
114
getBufferSize(size_t * size)115 status_t StreamHalAidl::getBufferSize(size_t *size) {
116 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
117 if (size == nullptr) {
118 return BAD_VALUE;
119 }
120 if (mContext.getFrameSizeBytes() == 0 || mContext.getBufferSizeFrames() == 0 ||
121 !mStream) {
122 return NO_INIT;
123 }
124 *size = mContext.getBufferSizeBytes();
125 return OK;
126 }
127
getAudioProperties(audio_config_base_t * configBase)128 status_t StreamHalAidl::getAudioProperties(audio_config_base_t *configBase) {
129 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
130 if (configBase == nullptr) {
131 return BAD_VALUE;
132 }
133 if (!mStream) return NO_INIT;
134 *configBase = mConfig;
135 return OK;
136 }
137
setParameters(const String8 & kvPairs)138 status_t StreamHalAidl::setParameters(const String8& kvPairs) {
139 TIME_CHECK();
140 if (!mStream) return NO_INIT;
141 AudioParameter parameters(kvPairs);
142 ALOGD("%s: parameters: %s", __func__, parameters.toString().c_str());
143
144 (void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
145 parameters, String8(AudioParameter::keyStreamHwAvSync),
146 [&](int hwAvSyncId) {
147 return statusTFromBinderStatus(mStream->updateHwAvSyncId(hwAvSyncId));
148 }));
149 return parseAndSetVendorParameters(mVendorExt, mStream, parameters);
150 }
151
getParameters(const String8 & keys __unused,String8 * values)152 status_t StreamHalAidl::getParameters(const String8& keys __unused, String8 *values) {
153 TIME_CHECK();
154 if (!mStream) return NO_INIT;
155 if (values == nullptr) {
156 return BAD_VALUE;
157 }
158 AudioParameter parameterKeys(keys), result;
159 *values = result.toString();
160 return parseAndGetVendorParameters(mVendorExt, mStream, parameterKeys, values);
161 }
162
getFrameSize(size_t * size)163 status_t StreamHalAidl::getFrameSize(size_t *size) {
164 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
165 if (size == nullptr) {
166 return BAD_VALUE;
167 }
168 if (mContext.getFrameSizeBytes() == 0 || !mStream) {
169 return NO_INIT;
170 }
171 *size = mContext.getFrameSizeBytes();
172 return OK;
173 }
174
addEffect(sp<EffectHalInterface> effect)175 status_t StreamHalAidl::addEffect(sp<EffectHalInterface> effect) {
176 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
177 TIME_CHECK();
178 if (!mStream) return NO_INIT;
179 if (effect == nullptr) {
180 return BAD_VALUE;
181 }
182 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
183 return statusTFromBinderStatus(mStream->addEffect(aidlEffect->getIEffect()));
184 }
185
removeEffect(sp<EffectHalInterface> effect)186 status_t StreamHalAidl::removeEffect(sp<EffectHalInterface> effect) {
187 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
188 TIME_CHECK();
189 if (!mStream) return NO_INIT;
190 if (effect == nullptr) {
191 return BAD_VALUE;
192 }
193 auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
194 return statusTFromBinderStatus(mStream->removeEffect(aidlEffect->getIEffect()));
195 }
196
standby()197 status_t StreamHalAidl::standby() {
198 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
199 TIME_CHECK();
200 if (!mStream) return NO_INIT;
201 const auto state = getState();
202 StreamDescriptor::Reply reply;
203 switch (state) {
204 case StreamDescriptor::State::ACTIVE:
205 case StreamDescriptor::State::DRAINING:
206 case StreamDescriptor::State::TRANSFERRING:
207 RETURN_STATUS_IF_ERROR(pause(&reply));
208 if (reply.state != StreamDescriptor::State::PAUSED &&
209 reply.state != StreamDescriptor::State::DRAIN_PAUSED &&
210 reply.state != StreamDescriptor::State::TRANSFER_PAUSED) {
211 ALOGE("%s: unexpected stream state: %s (expected PAUSED)",
212 __func__, toString(reply.state).c_str());
213 return INVALID_OPERATION;
214 }
215 FALLTHROUGH_INTENDED;
216 case StreamDescriptor::State::PAUSED:
217 case StreamDescriptor::State::DRAIN_PAUSED:
218 case StreamDescriptor::State::TRANSFER_PAUSED:
219 if (mIsInput) return flush();
220 RETURN_STATUS_IF_ERROR(flush(&reply));
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;
227 case StreamDescriptor::State::IDLE:
228 RETURN_STATUS_IF_ERROR(sendCommand(makeHalCommand<HalCommand::Tag::standby>(),
229 &reply, true /*safeFromNonWorkerThread*/));
230 if (reply.state != StreamDescriptor::State::STANDBY) {
231 ALOGE("%s: unexpected stream state: %s (expected STANDBY)",
232 __func__, toString(reply.state).c_str());
233 return INVALID_OPERATION;
234 }
235 FALLTHROUGH_INTENDED;
236 case StreamDescriptor::State::STANDBY:
237 return OK;
238 default:
239 ALOGE("%s: not supported from %s stream state %s",
240 __func__, mIsInput ? "input" : "output", toString(state).c_str());
241 return INVALID_OPERATION;
242 }
243 }
244
dump(int fd,const Vector<String16> & args)245 status_t StreamHalAidl::dump(int fd, const Vector<String16>& args) {
246 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
247 TIME_CHECK();
248 if (!mStream) return NO_INIT;
249 Vector<String16> newArgs = args;
250 newArgs.push(String16(kDumpFromAudioServerArgument));
251 status_t status = mStream->dump(fd, Args(newArgs).args(), newArgs.size());
252 mStreamPowerLog.dump(fd);
253 return status;
254 }
255
start()256 status_t StreamHalAidl::start() {
257 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
258 TIME_CHECK();
259 if (!mStream) return NO_INIT;
260 if (!mContext.isMmapped()) {
261 return BAD_VALUE;
262 }
263 StreamDescriptor::Reply reply;
264 RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
265 switch (reply.state) {
266 case StreamDescriptor::State::STANDBY:
267 RETURN_STATUS_IF_ERROR(
268 sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply, true));
269 if (reply.state != StreamDescriptor::State::IDLE) {
270 ALOGE("%s: unexpected stream state: %s (expected IDLE)",
271 __func__, toString(reply.state).c_str());
272 return INVALID_OPERATION;
273 }
274 FALLTHROUGH_INTENDED;
275 case StreamDescriptor::State::IDLE:
276 RETURN_STATUS_IF_ERROR(
277 sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), &reply, true));
278 if (reply.state != StreamDescriptor::State::ACTIVE) {
279 ALOGE("%s: unexpected stream state: %s (expected ACTIVE)",
280 __func__, toString(reply.state).c_str());
281 return INVALID_OPERATION;
282 }
283 FALLTHROUGH_INTENDED;
284 case StreamDescriptor::State::ACTIVE:
285 return OK;
286 case StreamDescriptor::State::DRAINING:
287 RETURN_STATUS_IF_ERROR(
288 sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply, true));
289 if (reply.state != StreamDescriptor::State::ACTIVE) {
290 ALOGE("%s: unexpected stream state: %s (expected ACTIVE)",
291 __func__, toString(reply.state).c_str());
292 return INVALID_OPERATION;
293 }
294 return OK;
295 default:
296 ALOGE("%s: not supported from %s stream state %s",
297 __func__, mIsInput ? "input" : "output", toString(reply.state).c_str());
298 return INVALID_OPERATION;
299 }
300 }
301
stop()302 status_t StreamHalAidl::stop() {
303 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
304 TIME_CHECK();
305 if (!mStream) return NO_INIT;
306 if (!mContext.isMmapped()) {
307 return BAD_VALUE;
308 }
309 StreamDescriptor::Reply reply;
310 RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
311 if (const auto state = reply.state; state == StreamDescriptor::State::ACTIVE) {
312 return drain(false /*earlyNotify*/, nullptr);
313 } else if (state == StreamDescriptor::State::DRAINING) {
314 RETURN_STATUS_IF_ERROR(pause());
315 return flush();
316 } else if (state == StreamDescriptor::State::PAUSED) {
317 return flush();
318 } else if (state != StreamDescriptor::State::IDLE &&
319 state != StreamDescriptor::State::STANDBY) {
320 ALOGE("%s: not supported from %s stream state %s",
321 __func__, mIsInput ? "input" : "output", toString(state).c_str());
322 return INVALID_OPERATION;
323 }
324 return OK;
325 }
326
getLatency(uint32_t * latency)327 status_t StreamHalAidl::getLatency(uint32_t *latency) {
328 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
329 if (!mStream) return NO_INIT;
330 StreamDescriptor::Reply reply;
331 RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
332 *latency = std::clamp(std::max<int32_t>(0, reply.latencyMs), 1, 3000);
333 ALOGW_IF(reply.latencyMs != static_cast<int32_t>(*latency),
334 "Suspicious latency value reported by HAL: %d, clamped to %u", reply.latencyMs,
335 *latency);
336 return OK;
337 }
338
getObservablePosition(int64_t * frames,int64_t * timestamp,StatePositions * statePositions)339 status_t StreamHalAidl::getObservablePosition(int64_t* frames, int64_t* timestamp,
340 StatePositions* statePositions) {
341 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
342 if (!mStream) return NO_INIT;
343 StreamDescriptor::Reply reply;
344 RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply, statePositions));
345 *frames = std::max<int64_t>(0, reply.observable.frames);
346 *timestamp = std::max<int64_t>(0, reply.observable.timeNs);
347 return OK;
348 }
349
getHardwarePosition(int64_t * frames,int64_t * timestamp)350 status_t StreamHalAidl::getHardwarePosition(int64_t *frames, int64_t *timestamp) {
351 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
352 if (!mStream) return NO_INIT;
353 StreamDescriptor::Reply reply;
354 RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
355 *frames = std::max<int64_t>(0, reply.hardware.frames);
356 *timestamp = std::max<int64_t>(0, reply.hardware.timeNs);
357 return OK;
358 }
359
getXruns(int32_t * frames)360 status_t StreamHalAidl::getXruns(int32_t *frames) {
361 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
362 if (!mStream) return NO_INIT;
363 StreamDescriptor::Reply reply;
364 RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
365 *frames = std::max<int32_t>(0, reply.xrunFrames);
366 return OK;
367 }
368
transfer(void * buffer,size_t bytes,size_t * transferred)369 status_t StreamHalAidl::transfer(void *buffer, size_t bytes, size_t *transferred) {
370 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
371 // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
372 if (!mStream || mContext.getDataMQ() == nullptr) return NO_INIT;
373 mWorkerTid.store(gettid(), std::memory_order_release);
374 // Switch the stream into an active state if needed.
375 // Note: in future we may add support for priming the audio pipeline
376 // with data prior to enabling output (thus we can issue a "burst" command in the "standby"
377 // stream state), however this scenario wasn't supported by the HIDL HAL.
378 if (getState() == StreamDescriptor::State::STANDBY) {
379 StreamDescriptor::Reply reply;
380 RETURN_STATUS_IF_ERROR(sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply));
381 if (reply.state != StreamDescriptor::State::IDLE) {
382 ALOGE("%s: failed to get the stream out of standby, actual state: %s",
383 __func__, toString(reply.state).c_str());
384 return INVALID_OPERATION;
385 }
386 }
387 StreamContextAidl::DataMQ::Error fmqError = StreamContextAidl::DataMQ::Error::NONE;
388 std::string fmqErrorMsg;
389 if (!mIsInput) {
390 bytes = std::min(bytes,
391 mContext.getDataMQ()->availableToWrite(&fmqError, &fmqErrorMsg));
392 }
393 StreamDescriptor::Command burst =
394 StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(bytes);
395 if (!mIsInput) {
396 if (!mContext.getDataMQ()->write(static_cast<const int8_t*>(buffer), bytes)) {
397 ALOGE("%s: failed to write %zu bytes to data MQ", __func__, bytes);
398 return NOT_ENOUGH_DATA;
399 }
400 }
401 StreamDescriptor::Reply reply;
402 RETURN_STATUS_IF_ERROR(sendCommand(burst, &reply));
403 *transferred = reply.fmqByteCount;
404 if (mIsInput) {
405 LOG_ALWAYS_FATAL_IF(*transferred > bytes,
406 "%s: HAL module read %zu bytes, which exceeds requested count %zu",
407 __func__, *transferred, bytes);
408 if (auto toRead = mContext.getDataMQ()->availableToRead(&fmqError, &fmqErrorMsg);
409 toRead != 0 && !mContext.getDataMQ()->read(static_cast<int8_t*>(buffer), toRead)) {
410 ALOGE("%s: failed to read %zu bytes to data MQ", __func__, toRead);
411 return NOT_ENOUGH_DATA;
412 }
413 }
414 LOG_ALWAYS_FATAL_IF(fmqError != StreamContextAidl::DataMQ::Error::NONE,
415 "%s", fmqErrorMsg.c_str());
416 mStreamPowerLog.log(buffer, *transferred);
417 return OK;
418 }
419
pause(StreamDescriptor::Reply * reply)420 status_t StreamHalAidl::pause(StreamDescriptor::Reply* reply) {
421 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
422 TIME_CHECK();
423 if (!mStream) return NO_INIT;
424 return sendCommand(makeHalCommand<HalCommand::Tag::pause>(), reply,
425 true /*safeFromNonWorkerThread*/); // The workers stops its I/O activity first.
426 }
427
resume(StreamDescriptor::Reply * reply)428 status_t StreamHalAidl::resume(StreamDescriptor::Reply* reply) {
429 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
430 TIME_CHECK();
431 if (!mStream) return NO_INIT;
432 if (mIsInput) {
433 return sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), reply);
434 } else {
435 if (const auto state = getState(); state == StreamDescriptor::State::IDLE) {
436 // Handle pause-flush-resume sequence. 'flush' from PAUSED goes to
437 // IDLE. We move here from IDLE to ACTIVE (same as 'start' from PAUSED).
438 StreamDescriptor::Reply localReply{};
439 StreamDescriptor::Reply* innerReply = reply ?: &localReply;
440 RETURN_STATUS_IF_ERROR(
441 sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), innerReply));
442 if (innerReply->state != StreamDescriptor::State::ACTIVE) {
443 ALOGE("%s: unexpected stream state: %s (expected ACTIVE)",
444 __func__, toString(innerReply->state).c_str());
445 return INVALID_OPERATION;
446 }
447 return OK;
448 } else if (state == StreamDescriptor::State::PAUSED ||
449 state == StreamDescriptor::State::TRANSFER_PAUSED ||
450 state == StreamDescriptor::State::DRAIN_PAUSED) {
451 return sendCommand(makeHalCommand<HalCommand::Tag::start>(), reply);
452 } else {
453 ALOGE("%s: unexpected stream state: %s (expected IDLE or one of *PAUSED states)",
454 __func__, toString(state).c_str());
455 return INVALID_OPERATION;
456 }
457 }
458 }
459
drain(bool earlyNotify,StreamDescriptor::Reply * reply)460 status_t StreamHalAidl::drain(bool earlyNotify, StreamDescriptor::Reply* reply) {
461 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
462 TIME_CHECK();
463 if (!mStream) return NO_INIT;
464 return sendCommand(makeHalCommand<HalCommand::Tag::drain>(
465 mIsInput ? StreamDescriptor::DrainMode::DRAIN_UNSPECIFIED :
466 earlyNotify ? StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY :
467 StreamDescriptor::DrainMode::DRAIN_ALL), reply,
468 true /*safeFromNonWorkerThread*/);
469 }
470
flush(StreamDescriptor::Reply * reply)471 status_t StreamHalAidl::flush(StreamDescriptor::Reply* reply) {
472 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
473 TIME_CHECK();
474 if (!mStream) return NO_INIT;
475 return sendCommand(makeHalCommand<HalCommand::Tag::flush>(), reply,
476 true /*safeFromNonWorkerThread*/); // The workers stops its I/O activity first.
477 }
478
exit()479 status_t StreamHalAidl::exit() {
480 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
481 TIME_CHECK();
482 if (!mStream) return NO_INIT;
483 return statusTFromBinderStatus(mStream->prepareToClose());
484 }
485
onAsyncTransferReady()486 void StreamHalAidl::onAsyncTransferReady() {
487 if (auto state = getState(); state == StreamDescriptor::State::TRANSFERRING) {
488 // Retrieve the current state together with position counters unconditionally
489 // to ensure that the state on our side gets updated.
490 sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(),
491 nullptr, true /*safeFromNonWorkerThread */);
492 } else {
493 ALOGW("%s: unexpected onTransferReady in the state %s", __func__, toString(state).c_str());
494 }
495 }
496
onAsyncDrainReady()497 void StreamHalAidl::onAsyncDrainReady() {
498 if (auto state = getState(); state == StreamDescriptor::State::DRAINING) {
499 // Retrieve the current state together with position counters unconditionally
500 // to ensure that the state on our side gets updated.
501 sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), nullptr,
502 true /*safeFromNonWorkerThread */);
503 // For compatibility with HIDL behavior, apply a "soft" position reset
504 // after receiving the "drain ready" callback.
505 std::lock_guard l(mLock);
506 mStatePositions.framesAtFlushOrDrain = mLastReply.observable.frames;
507 } else {
508 ALOGW("%s: unexpected onDrainReady in the state %s", __func__, toString(state).c_str());
509 }
510 }
511
onAsyncError()512 void StreamHalAidl::onAsyncError() {
513 std::lock_guard l(mLock);
514 ALOGW("%s: received in the state %s", __func__, toString(mLastReply.state).c_str());
515 mLastReply.state = StreamDescriptor::State::ERROR;
516 }
517
createMmapBuffer(int32_t minSizeFrames __unused,struct audio_mmap_buffer_info * info)518 status_t StreamHalAidl::createMmapBuffer(int32_t minSizeFrames __unused,
519 struct audio_mmap_buffer_info *info) {
520 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
521 TIME_CHECK();
522 if (!mStream) return NO_INIT;
523 if (!mContext.isMmapped()) {
524 return BAD_VALUE;
525 }
526 const MmapBufferDescriptor& bufferDescriptor = mContext.getMmapBufferDescriptor();
527 info->shared_memory_fd = bufferDescriptor.sharedMemory.fd.get();
528 info->buffer_size_frames = mContext.getBufferSizeFrames();
529 info->burst_size_frames = bufferDescriptor.burstSizeFrames;
530 info->flags = static_cast<audio_mmap_buffer_flag>(bufferDescriptor.flags);
531
532 return OK;
533 }
534
getMmapPosition(struct audio_mmap_position * position)535 status_t StreamHalAidl::getMmapPosition(struct audio_mmap_position *position) {
536 TIME_CHECK();
537 if (!mStream) return NO_INIT;
538 if (!mContext.isMmapped()) {
539 return BAD_VALUE;
540 }
541 int64_t aidlPosition = 0, aidlTimestamp = 0;
542 RETURN_STATUS_IF_ERROR(getHardwarePosition(&aidlPosition, &aidlTimestamp));
543 position->time_nanoseconds = aidlTimestamp;
544 position->position_frames = static_cast<int32_t>(aidlPosition);
545 return OK;
546 }
547
setHalThreadPriority(int priority __unused)548 status_t StreamHalAidl::setHalThreadPriority(int priority __unused) {
549 // Obsolete, must be done by the HAL module.
550 return OK;
551 }
552
legacyCreateAudioPatch(const struct audio_port_config & port __unused,std::optional<audio_source_t> source __unused,audio_devices_t type __unused)553 status_t StreamHalAidl::legacyCreateAudioPatch(const struct audio_port_config& port __unused,
554 std::optional<audio_source_t> source __unused,
555 audio_devices_t type __unused) {
556 // Obsolete since 'DeviceHalAidl.supportsAudioPatches' always returns 'true'.
557 return INVALID_OPERATION;
558 }
559
legacyReleaseAudioPatch()560 status_t StreamHalAidl::legacyReleaseAudioPatch() {
561 // Obsolete since 'DeviceHalAidl.supportsAudioPatches' always returns 'true'.
562 return INVALID_OPERATION;
563 }
564
sendCommand(const::aidl::android::hardware::audio::core::StreamDescriptor::Command & command,::aidl::android::hardware::audio::core::StreamDescriptor::Reply * reply,bool safeFromNonWorkerThread,StatePositions * statePositions)565 status_t StreamHalAidl::sendCommand(
566 const ::aidl::android::hardware::audio::core::StreamDescriptor::Command& command,
567 ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply,
568 bool safeFromNonWorkerThread, StatePositions* statePositions) {
569 // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
570 if (!safeFromNonWorkerThread) {
571 const pid_t workerTid = mWorkerTid.load(std::memory_order_acquire);
572 LOG_ALWAYS_FATAL_IF(workerTid != gettid(),
573 "%s %s: must be invoked from the worker thread (%d)",
574 __func__, command.toString().c_str(), workerTid);
575 }
576 StreamDescriptor::Reply localReply{};
577 {
578 std::lock_guard l(mCommandReplyLock);
579 if (!mContext.getCommandMQ()->writeBlocking(&command, 1)) {
580 ALOGE("%s: failed to write command %s to MQ", __func__, command.toString().c_str());
581 return NOT_ENOUGH_DATA;
582 }
583 if (reply == nullptr) {
584 reply = &localReply;
585 }
586 if (!mContext.getReplyMQ()->readBlocking(reply, 1)) {
587 ALOGE("%s: failed to read from reply MQ, command %s",
588 __func__, command.toString().c_str());
589 return NOT_ENOUGH_DATA;
590 }
591 {
592 std::lock_guard l(mLock);
593 // Not every command replies with 'latencyMs' field filled out, substitute the last
594 // returned value in that case.
595 if (reply->latencyMs <= 0) {
596 reply->latencyMs = mLastReply.latencyMs;
597 }
598 mLastReply = *reply;
599 mLastReplyExpirationNs = uptimeNanos() + mLastReplyLifeTimeNs;
600 if (!mIsInput && reply->status == STATUS_OK) {
601 if (command.getTag() == StreamDescriptor::Command::standby &&
602 reply->state == StreamDescriptor::State::STANDBY) {
603 mStatePositions.framesAtStandby = reply->observable.frames;
604 } else if (command.getTag() == StreamDescriptor::Command::flush &&
605 reply->state == StreamDescriptor::State::IDLE) {
606 mStatePositions.framesAtFlushOrDrain = reply->observable.frames;
607 } else if (!mContext.isAsynchronous() &&
608 command.getTag() == StreamDescriptor::Command::drain &&
609 (reply->state == StreamDescriptor::State::IDLE ||
610 reply->state == StreamDescriptor::State::DRAINING)) {
611 mStatePositions.framesAtFlushOrDrain = reply->observable.frames;
612 } // for asynchronous drain, the frame count is saved in 'onAsyncDrainReady'
613 }
614 if (statePositions != nullptr) {
615 *statePositions = mStatePositions;
616 }
617 }
618 }
619 switch (reply->status) {
620 case STATUS_OK: return OK;
621 case STATUS_BAD_VALUE: return BAD_VALUE;
622 case STATUS_INVALID_OPERATION: return INVALID_OPERATION;
623 case STATUS_NOT_ENOUGH_DATA: return NOT_ENOUGH_DATA;
624 default:
625 ALOGE("%s: unexpected status %d returned for command %s",
626 __func__, reply->status, command.toString().c_str());
627 return INVALID_OPERATION;
628 }
629 }
630
updateCountersIfNeeded(::aidl::android::hardware::audio::core::StreamDescriptor::Reply * reply,StatePositions * statePositions)631 status_t StreamHalAidl::updateCountersIfNeeded(
632 ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply,
633 StatePositions* statePositions) {
634 bool doUpdate = false;
635 {
636 std::lock_guard l(mLock);
637 doUpdate = uptimeNanos() > mLastReplyExpirationNs;
638 }
639 if (doUpdate) {
640 // Since updates are paced, it is OK to perform them from any thread, they should
641 // not interfere with I/O operations of the worker.
642 return sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(),
643 reply, true /*safeFromNonWorkerThread */, statePositions);
644 } else if (reply != nullptr) { // provide cached reply
645 std::lock_guard l(mLock);
646 *reply = mLastReply;
647 if (statePositions != nullptr) {
648 *statePositions = mStatePositions;
649 }
650 }
651 return OK;
652 }
653
654 // static
655 ConversionResult<::aidl::android::hardware::audio::common::SourceMetadata>
legacy2aidl_SourceMetadata(const StreamOutHalInterface::SourceMetadata & legacy)656 StreamOutHalAidl::legacy2aidl_SourceMetadata(const StreamOutHalInterface::SourceMetadata& legacy) {
657 ::aidl::android::hardware::audio::common::SourceMetadata aidl;
658 aidl.tracks = VALUE_OR_RETURN(
659 ::aidl::android::convertContainer<std::vector<PlaybackTrackMetadata>>(
660 legacy.tracks,
661 ::aidl::android::legacy2aidl_playback_track_metadata_v7_PlaybackTrackMetadata));
662 return aidl;
663 }
664
StreamOutHalAidl(const audio_config & config,StreamContextAidl && context,int32_t nominalLatency,const std::shared_ptr<IStreamOut> & stream,const std::shared_ptr<IHalAdapterVendorExtension> & vext,const sp<CallbackBroker> & callbackBroker)665 StreamOutHalAidl::StreamOutHalAidl(
666 const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
667 const std::shared_ptr<IStreamOut>& stream,
668 const std::shared_ptr<IHalAdapterVendorExtension>& vext,
669 const sp<CallbackBroker>& callbackBroker)
670 : StreamHalAidl("StreamOutHalAidl", false /*isInput*/, config, nominalLatency,
671 std::move(context), getStreamCommon(stream), vext),
672 mStream(stream), mCallbackBroker(callbackBroker) {
673 // Initialize the offload metadata
674 mOffloadMetadata.sampleRate = static_cast<int32_t>(config.sample_rate);
675 mOffloadMetadata.channelMask = VALUE_OR_FATAL(
676 ::aidl::android::legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
677 config.channel_mask, false));
678 mOffloadMetadata.averageBitRatePerSecond = static_cast<int32_t>(config.offload_info.bit_rate);
679 }
680
~StreamOutHalAidl()681 StreamOutHalAidl::~StreamOutHalAidl() {
682 if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
683 broker->clearCallbacks(static_cast<StreamOutHalInterface*>(this));
684 }
685 }
686
setParameters(const String8 & kvPairs)687 status_t StreamOutHalAidl::setParameters(const String8& kvPairs) {
688 if (!mStream) return NO_INIT;
689
690 AudioParameter parameters(kvPairs);
691 ALOGD("%s: parameters: \"%s\"", __func__, parameters.toString().c_str());
692
693 if (status_t status = filterAndUpdateOffloadMetadata(parameters); status != OK) {
694 ALOGW("%s: filtering or updating offload metadata failed: %d", __func__, status);
695 }
696
697 return StreamHalAidl::setParameters(parameters.toString());
698 }
699
getLatency(uint32_t * latency)700 status_t StreamOutHalAidl::getLatency(uint32_t *latency) {
701 return StreamHalAidl::getLatency(latency);
702 }
703
setVolume(float left,float right)704 status_t StreamOutHalAidl::setVolume(float left, float right) {
705 TIME_CHECK();
706 if (!mStream) return NO_INIT;
707 size_t channelCount = audio_channel_count_from_out_mask(mConfig.channel_mask);
708 if (channelCount == 0) channelCount = 2;
709 std::vector<float> volumes(channelCount);
710 if (channelCount == 1) {
711 volumes[0] = (left + right) / 2;
712 } else {
713 volumes[0] = left;
714 volumes[1] = right;
715 for (size_t i = 2; i < channelCount; ++i) {
716 volumes[i] = (left + right) / 2;
717 }
718 }
719 return statusTFromBinderStatus(mStream->setHwVolume(volumes));
720 }
721
selectPresentation(int presentationId,int programId)722 status_t StreamOutHalAidl::selectPresentation(int presentationId, int programId) {
723 TIME_CHECK();
724 if (!mStream) return NO_INIT;
725 return statusTFromBinderStatus(mStream->selectPresentation(presentationId, programId));
726 }
727
write(const void * buffer,size_t bytes,size_t * written)728 status_t StreamOutHalAidl::write(const void *buffer, size_t bytes, size_t *written) {
729 if (buffer == nullptr || written == nullptr) {
730 return BAD_VALUE;
731 }
732 // For the output scenario, 'transfer' does not modify the buffer.
733 return transfer(const_cast<void*>(buffer), bytes, written);
734 }
735
getRenderPosition(uint64_t * dspFrames)736 status_t StreamOutHalAidl::getRenderPosition(uint64_t *dspFrames) {
737 if (dspFrames == nullptr) {
738 return BAD_VALUE;
739 }
740 int64_t aidlFrames = 0, aidlTimestamp = 0;
741 StatePositions statePositions{};
742 RETURN_STATUS_IF_ERROR(
743 getObservablePosition(&aidlFrames, &aidlTimestamp, &statePositions));
744 // Number of audio frames since the stream has exited standby.
745 // See the table at the start of 'StreamHalInterface' on when it needs to reset.
746 int64_t mostRecentResetPoint;
747 if (!mContext.isAsynchronous() && audio_has_proportional_frames(mConfig.format)) {
748 mostRecentResetPoint = statePositions.framesAtStandby;
749 } else {
750 mostRecentResetPoint =
751 std::max(statePositions.framesAtStandby, statePositions.framesAtFlushOrDrain);
752 }
753 *dspFrames = aidlFrames <= mostRecentResetPoint ? 0 : aidlFrames - mostRecentResetPoint;
754 return OK;
755 }
756
setCallback(wp<StreamOutHalInterfaceCallback> callback)757 status_t StreamOutHalAidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
758 ALOGD("%p %s", this, __func__);
759 TIME_CHECK();
760 if (!mStream) return NO_INIT;
761 if (!mContext.isAsynchronous()) {
762 ALOGE("%s: the callback is intended for asynchronous streams only", __func__);
763 return INVALID_OPERATION;
764 }
765 mClientCallback = callback;
766 return OK;
767 }
768
supportsPauseAndResume(bool * supportsPause,bool * supportsResume)769 status_t StreamOutHalAidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
770 if (supportsPause == nullptr || supportsResume == nullptr) {
771 return BAD_VALUE;
772 }
773 TIME_CHECK();
774 if (!mStream) return NO_INIT;
775 *supportsPause = *supportsResume = true;
776 return OK;
777 }
778
pause()779 status_t StreamOutHalAidl::pause() {
780 return StreamHalAidl::pause();
781 }
782
resume()783 status_t StreamOutHalAidl::resume() {
784 return StreamHalAidl::resume();
785 }
786
supportsDrain(bool * supportsDrain)787 status_t StreamOutHalAidl::supportsDrain(bool *supportsDrain) {
788 if (supportsDrain == nullptr) {
789 return BAD_VALUE;
790 }
791 TIME_CHECK();
792 if (!mStream) return NO_INIT;
793 *supportsDrain = true;
794 return OK;
795 }
796
drain(bool earlyNotify)797 status_t StreamOutHalAidl::drain(bool earlyNotify) {
798 return StreamHalAidl::drain(earlyNotify);
799 }
800
flush()801 status_t StreamOutHalAidl::flush() {
802 return StreamHalAidl::flush();
803 }
804
getPresentationPosition(uint64_t * frames,struct timespec * timestamp)805 status_t StreamOutHalAidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
806 if (frames == nullptr || timestamp == nullptr) {
807 return BAD_VALUE;
808 }
809 int64_t aidlFrames = 0, aidlTimestamp = 0;
810 StatePositions statePositions{};
811 RETURN_STATUS_IF_ERROR(getObservablePosition(&aidlFrames, &aidlTimestamp, &statePositions));
812 // See the table at the start of 'StreamHalInterface'.
813 if (!mContext.isAsynchronous() && audio_has_proportional_frames(mConfig.format)) {
814 *frames = aidlFrames;
815 } else {
816 const int64_t mostRecentResetPoint =
817 std::max(statePositions.framesAtStandby, statePositions.framesAtFlushOrDrain);
818 *frames = aidlFrames <= mostRecentResetPoint ? 0 : aidlFrames - mostRecentResetPoint;
819 }
820 timestamp->tv_sec = aidlTimestamp / NANOS_PER_SECOND;
821 timestamp->tv_nsec = aidlTimestamp - timestamp->tv_sec * NANOS_PER_SECOND;
822 return OK;
823 }
824
presentationComplete()825 status_t StreamOutHalAidl::presentationComplete() {
826 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
827 return OK;
828 }
829
updateSourceMetadata(const StreamOutHalInterface::SourceMetadata & sourceMetadata)830 status_t StreamOutHalAidl::updateSourceMetadata(
831 const StreamOutHalInterface::SourceMetadata& sourceMetadata) {
832 TIME_CHECK();
833 if (!mStream) return NO_INIT;
834 ::aidl::android::hardware::audio::common::SourceMetadata aidlMetadata =
835 VALUE_OR_RETURN_STATUS(legacy2aidl_SourceMetadata(sourceMetadata));
836 return statusTFromBinderStatus(mStream->updateMetadata(aidlMetadata));
837 }
838
getDualMonoMode(audio_dual_mono_mode_t * mode)839 status_t StreamOutHalAidl::getDualMonoMode(audio_dual_mono_mode_t* mode) {
840 TIME_CHECK();
841 if (!mStream) return NO_INIT;
842 if (mode == nullptr) {
843 return BAD_VALUE;
844 }
845 ::aidl::android::media::audio::common::AudioDualMonoMode aidlMode;
846 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mStream->getDualMonoMode(&aidlMode)));
847 *mode = VALUE_OR_RETURN_STATUS(
848 ::aidl::android::aidl2legacy_AudioDualMonoMode_audio_dual_mono_mode_t(aidlMode));
849 return OK;
850 }
851
setDualMonoMode(audio_dual_mono_mode_t mode)852 status_t StreamOutHalAidl::setDualMonoMode(audio_dual_mono_mode_t mode) {
853 TIME_CHECK();
854 if (!mStream) return NO_INIT;
855 ::aidl::android::media::audio::common::AudioDualMonoMode aidlMode = VALUE_OR_RETURN_STATUS(
856 ::aidl::android::legacy2aidl_audio_dual_mono_mode_t_AudioDualMonoMode(mode));
857 return statusTFromBinderStatus(mStream->setDualMonoMode(aidlMode));
858 }
859
getAudioDescriptionMixLevel(float * leveldB)860 status_t StreamOutHalAidl::getAudioDescriptionMixLevel(float* leveldB) {
861 TIME_CHECK();
862 if (!mStream) return NO_INIT;
863 if (leveldB == nullptr) {
864 return BAD_VALUE;
865 }
866 return statusTFromBinderStatus(mStream->getAudioDescriptionMixLevel(leveldB));
867 }
868
setAudioDescriptionMixLevel(float leveldB)869 status_t StreamOutHalAidl::setAudioDescriptionMixLevel(float leveldB) {
870 TIME_CHECK();
871 if (!mStream) return NO_INIT;
872 return statusTFromBinderStatus(mStream->setAudioDescriptionMixLevel(leveldB));
873 }
874
getPlaybackRateParameters(audio_playback_rate_t * playbackRate)875 status_t StreamOutHalAidl::getPlaybackRateParameters(audio_playback_rate_t* playbackRate) {
876 TIME_CHECK();
877 if (!mStream) return NO_INIT;
878 if (playbackRate == nullptr) {
879 return BAD_VALUE;
880 }
881 ::aidl::android::media::audio::common::AudioPlaybackRate aidlRate;
882 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mStream->getPlaybackRateParameters(&aidlRate)));
883 *playbackRate = VALUE_OR_RETURN_STATUS(
884 ::aidl::android::aidl2legacy_AudioPlaybackRate_audio_playback_rate_t(aidlRate));
885 return OK;
886 }
887
setPlaybackRateParameters(const audio_playback_rate_t & playbackRate)888 status_t StreamOutHalAidl::setPlaybackRateParameters(const audio_playback_rate_t& playbackRate) {
889 TIME_CHECK();
890 if (!mStream) return NO_INIT;
891 ::aidl::android::media::audio::common::AudioPlaybackRate aidlRate = VALUE_OR_RETURN_STATUS(
892 ::aidl::android::legacy2aidl_audio_playback_rate_t_AudioPlaybackRate(playbackRate));
893 return statusTFromBinderStatus(mStream->setPlaybackRateParameters(aidlRate));
894 }
895
setEventCallback(const sp<StreamOutHalInterfaceEventCallback> & callback)896 status_t StreamOutHalAidl::setEventCallback(
897 const sp<StreamOutHalInterfaceEventCallback>& callback) {
898 TIME_CHECK();
899 if (!mStream) return NO_INIT;
900 if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
901 broker->setStreamOutEventCallback(static_cast<StreamOutHalInterface*>(this), callback);
902 }
903 return OK;
904 }
905
setLatencyMode(audio_latency_mode_t mode)906 status_t StreamOutHalAidl::setLatencyMode(audio_latency_mode_t mode) {
907 TIME_CHECK();
908 if (!mStream) return NO_INIT;
909 ::aidl::android::media::audio::common::AudioLatencyMode aidlMode = VALUE_OR_RETURN_STATUS(
910 ::aidl::android::legacy2aidl_audio_latency_mode_t_AudioLatencyMode(mode));
911 return statusTFromBinderStatus(mStream->setLatencyMode(aidlMode));
912 };
913
getRecommendedLatencyModes(std::vector<audio_latency_mode_t> * modes)914 status_t StreamOutHalAidl::getRecommendedLatencyModes(std::vector<audio_latency_mode_t> *modes) {
915 TIME_CHECK();
916 if (!mStream) return NO_INIT;
917 if (modes == nullptr) {
918 return BAD_VALUE;
919 }
920 std::vector<::aidl::android::media::audio::common::AudioLatencyMode> aidlModes;
921 RETURN_STATUS_IF_ERROR(
922 statusTFromBinderStatus(mStream->getRecommendedLatencyModes(&aidlModes)));
923 *modes = VALUE_OR_RETURN_STATUS(
924 ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>(
925 aidlModes,
926 ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
927 return OK;
928 };
929
setLatencyModeCallback(const sp<StreamOutHalInterfaceLatencyModeCallback> & callback)930 status_t StreamOutHalAidl::setLatencyModeCallback(
931 const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) {
932 TIME_CHECK();
933 if (!mStream) return NO_INIT;
934 if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
935 broker->setStreamOutLatencyModeCallback(
936 static_cast<StreamOutHalInterface*>(this), callback);
937 }
938 return OK;
939 };
940
exit()941 status_t StreamOutHalAidl::exit() {
942 return StreamHalAidl::exit();
943 }
944
onWriteReady()945 void StreamOutHalAidl::onWriteReady() {
946 onAsyncTransferReady();
947 if (auto clientCb = mClientCallback.load().promote(); clientCb != nullptr) {
948 clientCb->onWriteReady();
949 }
950 }
951
onDrainReady()952 void StreamOutHalAidl::onDrainReady() {
953 onAsyncDrainReady();
954 if (auto clientCb = mClientCallback.load().promote(); clientCb != nullptr) {
955 clientCb->onDrainReady();
956 }
957 }
958
onError(bool isHardError)959 void StreamOutHalAidl::onError(bool isHardError) {
960 onAsyncError();
961 if (auto clientCb = mClientCallback.load().promote(); clientCb != nullptr) {
962 clientCb->onError(isHardError);
963 }
964 }
965
filterAndUpdateOffloadMetadata(AudioParameter & parameters)966 status_t StreamOutHalAidl::filterAndUpdateOffloadMetadata(AudioParameter ¶meters) {
967 TIME_CHECK();
968 bool updateMetadata = false;
969 if (VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
970 parameters, String8(AudioParameter::keyOffloadCodecAverageBitRate),
971 [&](int value) {
972 return value >= 0 ?
973 mOffloadMetadata.averageBitRatePerSecond = value, OK : BAD_VALUE;
974 }))) {
975 updateMetadata = true;
976 }
977 if (VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
978 parameters, String8(AudioParameter::keyOffloadCodecSampleRate),
979 [&](int value) {
980 return value > 0 ? mOffloadMetadata.sampleRate = value, OK : BAD_VALUE;
981 }))) {
982 updateMetadata = true;
983 }
984 if (VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
985 parameters, String8(AudioParameter::keyOffloadCodecChannels),
986 [&](int value) -> status_t {
987 if (value > 0) {
988 audio_channel_mask_t channel_mask = audio_channel_out_mask_from_count(
989 static_cast<uint32_t>(value));
990 if (channel_mask == AUDIO_CHANNEL_INVALID) return BAD_VALUE;
991 mOffloadMetadata.channelMask = VALUE_OR_RETURN_STATUS(
992 ::aidl::android::legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
993 channel_mask, false /*isInput*/));
994 return OK;
995 }
996 return BAD_VALUE;
997 }))) {
998 updateMetadata = true;
999 }
1000 if (VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1001 parameters, String8(AudioParameter::keyOffloadCodecDelaySamples),
1002 [&](int value) {
1003 // The legacy keys are misnamed, the value is in frames.
1004 return value >= 0 ? mOffloadMetadata.delayFrames = value, OK : BAD_VALUE;
1005 }))) {
1006 updateMetadata = true;
1007 }
1008 if (VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
1009 parameters, String8(AudioParameter::keyOffloadCodecPaddingSamples),
1010 [&](int value) {
1011 // The legacy keys are misnamed, the value is in frames.
1012 return value >= 0 ? mOffloadMetadata.paddingFrames = value, OK : BAD_VALUE;
1013 }))) {
1014 updateMetadata = true;
1015 }
1016 if (updateMetadata) {
1017 ALOGD("%s set offload metadata %s", __func__, mOffloadMetadata.toString().c_str());
1018 if (status_t status = statusTFromBinderStatus(
1019 mStream->updateOffloadMetadata(mOffloadMetadata)); status != OK) {
1020 ALOGE("%s: updateOffloadMetadata failed %d", __func__, status);
1021 return status;
1022 }
1023 }
1024 return OK;
1025 }
1026
1027 // static
1028 ConversionResult<::aidl::android::hardware::audio::common::SinkMetadata>
legacy2aidl_SinkMetadata(const StreamInHalInterface::SinkMetadata & legacy)1029 StreamInHalAidl::legacy2aidl_SinkMetadata(const StreamInHalInterface::SinkMetadata& legacy) {
1030 ::aidl::android::hardware::audio::common::SinkMetadata aidl;
1031 aidl.tracks = VALUE_OR_RETURN(
1032 ::aidl::android::convertContainer<std::vector<RecordTrackMetadata>>(
1033 legacy.tracks,
1034 ::aidl::android::legacy2aidl_record_track_metadata_v7_RecordTrackMetadata));
1035 return aidl;
1036 }
1037
StreamInHalAidl(const audio_config & config,StreamContextAidl && context,int32_t nominalLatency,const std::shared_ptr<IStreamIn> & stream,const std::shared_ptr<IHalAdapterVendorExtension> & vext,const sp<MicrophoneInfoProvider> & micInfoProvider)1038 StreamInHalAidl::StreamInHalAidl(
1039 const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
1040 const std::shared_ptr<IStreamIn>& stream,
1041 const std::shared_ptr<IHalAdapterVendorExtension>& vext,
1042 const sp<MicrophoneInfoProvider>& micInfoProvider)
1043 : StreamHalAidl("StreamInHalAidl", true /*isInput*/, config, nominalLatency,
1044 std::move(context), getStreamCommon(stream), vext),
1045 mStream(stream), mMicInfoProvider(micInfoProvider) {}
1046
setGain(float gain)1047 status_t StreamInHalAidl::setGain(float gain) {
1048 TIME_CHECK();
1049 if (!mStream) return NO_INIT;
1050 const size_t channelCount = audio_channel_count_from_in_mask(mConfig.channel_mask);
1051 std::vector<float> gains(channelCount != 0 ? channelCount : 1, gain);
1052 return statusTFromBinderStatus(mStream->setHwGain(gains));
1053 }
1054
read(void * buffer,size_t bytes,size_t * read)1055 status_t StreamInHalAidl::read(void *buffer, size_t bytes, size_t *read) {
1056 if (buffer == nullptr || read == nullptr) {
1057 return BAD_VALUE;
1058 }
1059 return transfer(buffer, bytes, read);
1060 }
1061
getInputFramesLost(uint32_t * framesLost)1062 status_t StreamInHalAidl::getInputFramesLost(uint32_t *framesLost) {
1063 if (framesLost == nullptr) {
1064 return BAD_VALUE;
1065 }
1066 int32_t aidlXruns = 0;
1067 RETURN_STATUS_IF_ERROR(getXruns(&aidlXruns));
1068 *framesLost = std::max<int32_t>(0, aidlXruns);
1069 return OK;
1070 }
1071
getCapturePosition(int64_t * frames,int64_t * time)1072 status_t StreamInHalAidl::getCapturePosition(int64_t *frames, int64_t *time) {
1073 if (frames == nullptr || time == nullptr) {
1074 return BAD_VALUE;
1075 }
1076 return getObservablePosition(frames, time);
1077 }
1078
getActiveMicrophones(std::vector<media::MicrophoneInfoFw> * microphones)1079 status_t StreamInHalAidl::getActiveMicrophones(std::vector<media::MicrophoneInfoFw> *microphones) {
1080 if (!microphones) {
1081 return BAD_VALUE;
1082 }
1083 TIME_CHECK();
1084 if (!mStream) return NO_INIT;
1085 sp<MicrophoneInfoProvider> micInfoProvider = mMicInfoProvider.promote();
1086 if (!micInfoProvider) return NO_INIT;
1087 auto staticInfo = micInfoProvider->getMicrophoneInfo();
1088 if (!staticInfo) return INVALID_OPERATION;
1089 std::vector<MicrophoneDynamicInfo> dynamicInfo;
1090 RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mStream->getActiveMicrophones(&dynamicInfo)));
1091 std::vector<media::MicrophoneInfoFw> result;
1092 result.reserve(dynamicInfo.size());
1093 for (const auto& d : dynamicInfo) {
1094 const auto staticInfoIt = std::find_if(staticInfo->begin(), staticInfo->end(),
1095 [&](const auto& s) { return s.id == d.id; });
1096 if (staticInfoIt != staticInfo->end()) {
1097 // Convert into the c++ backend type from the ndk backend type via the legacy structure.
1098 audio_microphone_characteristic_t legacy = VALUE_OR_RETURN_STATUS(
1099 ::aidl::android::aidl2legacy_MicrophoneInfos_audio_microphone_characteristic_t(
1100 *staticInfoIt, d));
1101 media::MicrophoneInfoFw info = VALUE_OR_RETURN_STATUS(
1102 ::android::legacy2aidl_audio_microphone_characteristic_t_MicrophoneInfoFw(
1103 legacy));
1104 // Note: info.portId is not filled because it's a bit of framework info.
1105 result.push_back(std::move(info));
1106 } else {
1107 ALOGE("%s: no static info for active microphone with id '%s'", __func__, d.id.c_str());
1108 }
1109 }
1110 *microphones = std::move(result);
1111 return OK;
1112 }
1113
updateSinkMetadata(const StreamInHalInterface::SinkMetadata & sinkMetadata)1114 status_t StreamInHalAidl::updateSinkMetadata(
1115 const StreamInHalInterface::SinkMetadata& sinkMetadata) {
1116 TIME_CHECK();
1117 if (!mStream) return NO_INIT;
1118 ::aidl::android::hardware::audio::common::SinkMetadata aidlMetadata =
1119 VALUE_OR_RETURN_STATUS(legacy2aidl_SinkMetadata(sinkMetadata));
1120 return statusTFromBinderStatus(mStream->updateMetadata(aidlMetadata));
1121 }
1122
setPreferredMicrophoneDirection(audio_microphone_direction_t direction)1123 status_t StreamInHalAidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
1124 TIME_CHECK();
1125 if (!mStream) return NO_INIT;
1126 ::aidl::android::hardware::audio::core::IStreamIn::MicrophoneDirection aidlDirection =
1127 VALUE_OR_RETURN_STATUS(
1128 ::aidl::android::legacy2aidl_audio_microphone_direction_t_MicrophoneDirection(
1129 direction));
1130 return statusTFromBinderStatus(mStream->setMicrophoneDirection(aidlDirection));
1131 }
1132
setPreferredMicrophoneFieldDimension(float zoom)1133 status_t StreamInHalAidl::setPreferredMicrophoneFieldDimension(float zoom) {
1134 TIME_CHECK();
1135 if (!mStream) return NO_INIT;
1136 return statusTFromBinderStatus(mStream->setMicrophoneFieldDimension(zoom));
1137 }
1138
1139 } // namespace android
1140