blob: 39c3f4aa760fb2ae5f765ec43710c64fb53032c6 [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>
David Lia6fb5752023-02-23 15:32:47 +000024#include <media/AidlConversionUtil.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000025#include <mediautils/TimeCheck.h>
26#include <utils/Log.h>
27
28#include "DeviceHalAidl.h"
29#include "StreamHalAidl.h"
30
David Lia6fb5752023-02-23 15:32:47 +000031using ::aidl::android::aidl_utils::statusTFromBinderStatus;
Mikhail Naganov31d46652023-01-10 18:29:25 +000032using ::aidl::android::hardware::audio::core::IStreamCommon;
33using ::aidl::android::hardware::audio::core::IStreamIn;
34using ::aidl::android::hardware::audio::core::IStreamOut;
35using ::aidl::android::hardware::audio::core::StreamDescriptor;
36
37namespace android {
38
Mikhail Naganov89a9f742023-01-30 12:33:18 -080039using HalCommand = StreamDescriptor::Command;
40namespace {
41template<HalCommand::Tag cmd> HalCommand makeHalCommand() {
42 return HalCommand::make<cmd>(::aidl::android::media::audio::common::Void{});
43}
44template<HalCommand::Tag cmd, typename T> HalCommand makeHalCommand(T data) {
45 return HalCommand::make<cmd>(data);
46}
47} // namespace
48
Mikhail Naganovfab697c2023-01-11 19:33:13 +000049// static
50template<class T>
51std::shared_ptr<IStreamCommon> StreamHalAidl::getStreamCommon(const std::shared_ptr<T>& stream) {
52 std::shared_ptr<::aidl::android::hardware::audio::core::IStreamCommon> streamCommon;
53 if (stream != nullptr) {
54 if (ndk::ScopedAStatus status = stream->getStreamCommon(&streamCommon);
55 !status.isOk()) {
56 ALOGE("%s: failed to retrieve IStreamCommon instance: %s", __func__,
57 status.getDescription().c_str());
58 }
59 }
60 return streamCommon;
61}
62
Mikhail Naganov31d46652023-01-10 18:29:25 +000063StreamHalAidl::StreamHalAidl(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080064 std::string_view className, bool isInput, const audio_config& config,
Mikhail Naganov89a9f742023-01-30 12:33:18 -080065 int32_t nominalLatency, StreamContextAidl&& context,
66 const std::shared_ptr<IStreamCommon>& stream)
Mikhail Naganov31d46652023-01-10 18:29:25 +000067 : ConversionHelperAidl(className),
68 mIsInput(isInput),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080069 mConfig(configToBase(config)),
Mikhail Naganov89a9f742023-01-30 12:33:18 -080070 mContext(std::move(context)),
Mikhail Naganov31d46652023-01-10 18:29:25 +000071 mStream(stream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -080072 {
73 std::lock_guard l(mLock);
74 mLastReply.latencyMs = nominalLatency;
75 }
Mikhail Naganov31d46652023-01-10 18:29:25 +000076 // Instrument audio signal power logging.
77 // Note: This assumes channel mask, format, and sample rate do not change after creation.
78 if (audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
79 /* mStreamPowerLog.isUserDebugOrEngBuild() && */
80 StreamHalAidl::getAudioProperties(&config) == NO_ERROR) {
81 mStreamPowerLog.init(config.sample_rate, config.channel_mask, config.format);
82 }
83}
84
85StreamHalAidl::~StreamHalAidl() {
86 if (mStream != nullptr) {
87 ndk::ScopedAStatus status = mStream->close();
88 ALOGE_IF(!status.isOk(), "%s: status %s", __func__, status.getDescription().c_str());
89 }
90}
91
92status_t StreamHalAidl::getBufferSize(size_t *size) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -080093 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +000094 if (size == nullptr) {
95 return BAD_VALUE;
96 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -080097 if (mContext.getFrameSizeBytes() == 0 || mContext.getBufferSizeFrames() == 0 ||
98 !mStream) {
Mikhail Naganov31d46652023-01-10 18:29:25 +000099 return NO_INIT;
100 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800101 *size = mContext.getBufferSizeBytes();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000102 return OK;
103}
104
105status_t StreamHalAidl::getAudioProperties(audio_config_base_t *configBase) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800106 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000107 if (configBase == nullptr) {
108 return BAD_VALUE;
109 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800110 if (!mStream) return NO_INIT;
111 *configBase = mConfig;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000112 return OK;
113}
114
115status_t StreamHalAidl::setParameters(const String8& kvPairs __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800116 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000117 TIME_CHECK();
118 if (!mStream) return NO_INIT;
119 ALOGE("%s not implemented yet", __func__);
120 return OK;
121}
122
123status_t StreamHalAidl::getParameters(const String8& keys __unused, String8 *values) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800124 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000125 TIME_CHECK();
126 values->clear();
127 if (!mStream) return NO_INIT;
128 ALOGE("%s not implemented yet", __func__);
129 return OK;
130}
131
132status_t StreamHalAidl::getFrameSize(size_t *size) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800133 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000134 if (size == nullptr) {
135 return BAD_VALUE;
136 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800137 if (mContext.getFrameSizeBytes() == 0 || !mStream) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000138 return NO_INIT;
139 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800140 *size = mContext.getFrameSizeBytes();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000141 return OK;
142}
143
144status_t StreamHalAidl::addEffect(sp<EffectHalInterface> effect __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800145 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000146 TIME_CHECK();
147 if (!mStream) return NO_INIT;
148 ALOGE("%s not implemented yet", __func__);
149 return OK;
150}
151
152status_t StreamHalAidl::removeEffect(sp<EffectHalInterface> effect __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800153 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000154 TIME_CHECK();
155 if (!mStream) return NO_INIT;
156 ALOGE("%s not implemented yet", __func__);
157 return OK;
158}
159
160status_t StreamHalAidl::standby() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800161 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000162 TIME_CHECK();
163 if (!mStream) return NO_INIT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800164 const auto state = getState();
165 StreamDescriptor::Reply reply;
166 switch (state) {
167 case StreamDescriptor::State::ACTIVE:
168 if (status_t status = pause(&reply); status != OK) return status;
169 if (reply.state != StreamDescriptor::State::PAUSED) {
170 ALOGE("%s: unexpected stream state: %s (expected PAUSED)",
171 __func__, toString(reply.state).c_str());
172 return INVALID_OPERATION;
173 }
174 FALLTHROUGH_INTENDED;
175 case StreamDescriptor::State::PAUSED:
176 case StreamDescriptor::State::DRAIN_PAUSED:
Jasmine Cha105c66f2023-02-15 16:29:36 +0800177 if (mIsInput) return flush();
178 if (status_t status = flush(&reply); status != OK) return status;
179 if (reply.state != StreamDescriptor::State::IDLE) {
180 ALOGE("%s: unexpected stream state: %s (expected IDLE)",
181 __func__, toString(reply.state).c_str());
182 return INVALID_OPERATION;
183 }
184 FALLTHROUGH_INTENDED;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800185 case StreamDescriptor::State::IDLE:
186 if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::standby>(),
Jasmine Cha105c66f2023-02-15 16:29:36 +0800187 &reply, true /*safeFromNonWorkerThread*/); status != OK) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800188 return status;
189 }
190 if (reply.state != StreamDescriptor::State::STANDBY) {
191 ALOGE("%s: unexpected stream state: %s (expected STANDBY)",
192 __func__, toString(reply.state).c_str());
193 return INVALID_OPERATION;
194 }
195 FALLTHROUGH_INTENDED;
196 case StreamDescriptor::State::STANDBY:
197 return OK;
198 default:
199 ALOGE("%s: not supported from %s stream state %s",
200 __func__, mIsInput ? "input" : "output", toString(state).c_str());
201 return INVALID_OPERATION;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800202 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000203}
204
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000205status_t StreamHalAidl::dump(int fd, const Vector<String16>& args) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800206 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000207 TIME_CHECK();
208 if (!mStream) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000209 return mStream->dump(fd, Args(args).args(), args.size());
Mikhail Naganov31d46652023-01-10 18:29:25 +0000210}
211
212status_t StreamHalAidl::start() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800213 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000214 TIME_CHECK();
215 if (!mStream) return NO_INIT;
216 ALOGE("%s not implemented yet", __func__);
217 return OK;
218}
219
220status_t StreamHalAidl::stop() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800221 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
222 TIME_CHECK();
223 if (!mStream) return NO_INIT;
224 ALOGE("%s not implemented yet", __func__);
225 return OK;
226}
227
228status_t StreamHalAidl::getLatency(uint32_t *latency) {
229 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
230 if (!mStream) return NO_INIT;
231 StreamDescriptor::Reply reply;
232 if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
233 return status;
234 }
235 *latency = std::max<int32_t>(0, reply.latencyMs);
236 return OK;
237}
238
239status_t StreamHalAidl::getObservablePosition(int64_t *frames, int64_t *timestamp) {
240 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
241 if (!mStream) return NO_INIT;
242 StreamDescriptor::Reply reply;
243 if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
244 return status;
245 }
246 *frames = reply.observable.frames;
247 *timestamp = reply.observable.timeNs;
248 return OK;
249}
250
251status_t StreamHalAidl::getXruns(int32_t *frames) {
252 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
253 if (!mStream) return NO_INIT;
254 StreamDescriptor::Reply reply;
255 if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
256 return status;
257 }
258 *frames = reply.xrunFrames;
259 return OK;
260}
261
262status_t StreamHalAidl::transfer(void *buffer, size_t bytes, size_t *transferred) {
263 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
264 // TIME_CHECK(); // TODO(b/238654698) reenable only when optimized.
265 if (!mStream || mContext.getDataMQ() == nullptr) return NO_INIT;
266 mWorkerTid.store(gettid(), std::memory_order_release);
267 // Switch the stream into an active state if needed.
268 // Note: in future we may add support for priming the audio pipeline
269 // with data prior to enabling output (thus we can issue a "burst" command in the "standby"
270 // stream state), however this scenario wasn't supported by the HIDL HAL.
271 if (getState() == StreamDescriptor::State::STANDBY) {
272 StreamDescriptor::Reply reply;
273 if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply);
274 status != OK) {
275 return status;
276 }
277 if (reply.state != StreamDescriptor::State::IDLE) {
278 ALOGE("%s: failed to get the stream out of standby, actual state: %s",
279 __func__, toString(reply.state).c_str());
280 return INVALID_OPERATION;
281 }
282 }
283 if (!mIsInput) {
284 bytes = std::min(bytes, mContext.getDataMQ()->availableToWrite());
285 }
286 StreamDescriptor::Command burst =
287 StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(bytes);
288 if (!mIsInput) {
289 if (!mContext.getDataMQ()->write(static_cast<const int8_t*>(buffer), bytes)) {
290 ALOGE("%s: failed to write %zu bytes to data MQ", __func__, bytes);
291 return NOT_ENOUGH_DATA;
292 }
293 }
294 StreamDescriptor::Reply reply;
295 if (status_t status = sendCommand(burst, &reply); status != OK) {
296 return status;
297 }
Jasmine Chaad99fb02023-02-10 12:52:58 +0800298 *transferred = reply.fmqByteCount;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800299 if (mIsInput) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800300 LOG_ALWAYS_FATAL_IF(*transferred > bytes,
301 "%s: HAL module read %zu bytes, which exceeds requested count %zu",
302 __func__, *transferred, bytes);
Jasmine Cha105c66f2023-02-15 16:29:36 +0800303 if (auto toRead = mContext.getDataMQ()->availableToRead();
304 toRead != 0 && !mContext.getDataMQ()->read(static_cast<int8_t*>(buffer), toRead)) {
305 ALOGE("%s: failed to read %zu bytes to data MQ", __func__, toRead);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800306 return NOT_ENOUGH_DATA;
307 }
308 }
309 mStreamPowerLog.log(buffer, *transferred);
310 return OK;
311}
312
313status_t StreamHalAidl::pause(StreamDescriptor::Reply* reply) {
314 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
315 TIME_CHECK();
316 if (!mStream) return NO_INIT;
317 return sendCommand(makeHalCommand<HalCommand::Tag::pause>(), reply,
318 true /*safeFromNonWorkerThread*/); // The workers stops its I/O activity first.
319}
320
321status_t StreamHalAidl::resume(StreamDescriptor::Reply* reply) {
322 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
323 TIME_CHECK();
324 if (!mStream) return NO_INIT;
325 if (mIsInput) {
326 return sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), reply);
327 } else {
328 return sendCommand(makeHalCommand<HalCommand::Tag::start>(), reply);
329 }
330}
331
332status_t StreamHalAidl::drain(bool earlyNotify, StreamDescriptor::Reply* reply) {
333 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
334 TIME_CHECK();
335 if (!mStream) return NO_INIT;
336 return sendCommand(makeHalCommand<HalCommand::Tag::drain>(
337 mIsInput ? StreamDescriptor::DrainMode::DRAIN_UNSPECIFIED :
338 earlyNotify ? StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY :
David Lia6fb5752023-02-23 15:32:47 +0000339 StreamDescriptor::DrainMode::DRAIN_ALL), reply,
340 true /*safeFromNonWorkerThread*/);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800341}
342
343status_t StreamHalAidl::flush(StreamDescriptor::Reply* reply) {
344 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
345 TIME_CHECK();
346 if (!mStream) return NO_INIT;
347 return sendCommand(makeHalCommand<HalCommand::Tag::flush>(), reply,
348 true /*safeFromNonWorkerThread*/); // The workers stops its I/O activity first.
349}
350
351status_t StreamHalAidl::exit() {
352 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000353 TIME_CHECK();
354 if (!mStream) return NO_INIT;
355 ALOGE("%s not implemented yet", __func__);
356 return OK;
357}
358
359status_t StreamHalAidl::createMmapBuffer(int32_t minSizeFrames __unused,
360 struct audio_mmap_buffer_info *info __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800361 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000362 TIME_CHECK();
363 if (!mStream) return NO_INIT;
364 ALOGE("%s not implemented yet", __func__);
365 return OK;
366}
367
368status_t StreamHalAidl::getMmapPosition(struct audio_mmap_position *position __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800369 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000370 TIME_CHECK();
371 if (!mStream) return NO_INIT;
372 ALOGE("%s not implemented yet", __func__);
373 return OK;
374}
375
376status_t StreamHalAidl::setHalThreadPriority(int priority __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800377 // Obsolete, must be done by the HAL module.
Mikhail Naganov31d46652023-01-10 18:29:25 +0000378 return OK;
379}
380
381status_t StreamHalAidl::getHalPid(pid_t *pid __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800382 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000383 TIME_CHECK();
384 if (!mStream) return NO_INIT;
385 ALOGE("%s not implemented yet", __func__);
386 return OK;
387}
388
389bool StreamHalAidl::requestHalThreadPriority(pid_t threadPid __unused, pid_t threadId __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800390 // Obsolete, must be done by the HAL module.
391 return true;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000392}
393
394status_t StreamHalAidl::legacyCreateAudioPatch(const struct audio_port_config& port __unused,
395 std::optional<audio_source_t> source __unused,
396 audio_devices_t type __unused) {
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000397 // Obsolete since 'DeviceHalAidl.supportsAudioPatches' always returns 'true'.
398 return INVALID_OPERATION;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000399}
400
401status_t StreamHalAidl::legacyReleaseAudioPatch() {
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000402 // Obsolete since 'DeviceHalAidl.supportsAudioPatches' always returns 'true'.
403 return INVALID_OPERATION;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000404}
405
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800406status_t StreamHalAidl::sendCommand(
407 const ::aidl::android::hardware::audio::core::StreamDescriptor::Command &command,
408 ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply,
409 bool safeFromNonWorkerThread) {
410 // TIME_CHECK(); // TODO(b/238654698) reenable only when optimized.
411 if (!safeFromNonWorkerThread) {
412 const pid_t workerTid = mWorkerTid.load(std::memory_order_acquire);
413 LOG_ALWAYS_FATAL_IF(workerTid != gettid(),
414 "%s %s: must be invoked from the worker thread (%d)",
415 __func__, command.toString().c_str(), workerTid);
416 }
417 if (!mContext.getCommandMQ()->writeBlocking(&command, 1)) {
418 ALOGE("%s: failed to write command %s to MQ", __func__, command.toString().c_str());
419 return NOT_ENOUGH_DATA;
420 }
421 StreamDescriptor::Reply localReply{};
422 if (reply == nullptr) {
423 reply = &localReply;
424 }
425 if (!mContext.getReplyMQ()->readBlocking(reply, 1)) {
426 ALOGE("%s: failed to read from reply MQ, command %s", __func__, command.toString().c_str());
427 return NOT_ENOUGH_DATA;
428 }
429 {
430 std::lock_guard l(mLock);
431 mLastReply = *reply;
432 }
433 switch (reply->status) {
434 case STATUS_OK: return OK;
435 case STATUS_BAD_VALUE: return BAD_VALUE;
436 case STATUS_INVALID_OPERATION: return INVALID_OPERATION;
437 case STATUS_NOT_ENOUGH_DATA: return NOT_ENOUGH_DATA;
438 default:
439 ALOGE("%s: unexpected status %d returned for command %s",
440 __func__, reply->status, command.toString().c_str());
441 return INVALID_OPERATION;
442 }
443}
444
445status_t StreamHalAidl::updateCountersIfNeeded(
446 ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply) {
447 if (mWorkerTid.load(std::memory_order_acquire) == gettid()) {
448 if (const auto state = getState(); state != StreamDescriptor::State::ACTIVE &&
449 state != StreamDescriptor::State::DRAINING &&
450 state != StreamDescriptor::State::TRANSFERRING) {
451 return sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), reply);
452 }
453 }
454 if (reply != nullptr) {
455 std::lock_guard l(mLock);
456 *reply = mLastReply;
457 }
458 return OK;
459}
460
Mikhail Naganov31d46652023-01-10 18:29:25 +0000461StreamOutHalAidl::StreamOutHalAidl(
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800462 const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800463 const std::shared_ptr<IStreamOut>& stream, const sp<CallbackBroker>& callbackBroker)
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800464 : StreamHalAidl("StreamOutHalAidl", false /*isInput*/, config, nominalLatency,
465 std::move(context), getStreamCommon(stream)),
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800466 mStream(stream), mCallbackBroker(callbackBroker) {}
467
468StreamOutHalAidl::~StreamOutHalAidl() {
469 if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
470 broker->clearCallbacks(this);
471 }
472}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000473
474status_t StreamOutHalAidl::getLatency(uint32_t *latency) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800475 return StreamHalAidl::getLatency(latency);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000476}
477
David Lia6fb5752023-02-23 15:32:47 +0000478status_t StreamOutHalAidl::setVolume(float left, float right) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000479 TIME_CHECK();
480 if (!mStream) return NO_INIT;
David Lia6fb5752023-02-23 15:32:47 +0000481 return statusTFromBinderStatus(mStream->setHwVolume({left, right}));
Mikhail Naganov31d46652023-01-10 18:29:25 +0000482}
483
484status_t StreamOutHalAidl::selectPresentation(int presentationId __unused, int programId __unused) {
485 TIME_CHECK();
486 if (!mStream) return NO_INIT;
487 ALOGE("%s not implemented yet", __func__);
488 return OK;
489}
490
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800491status_t StreamOutHalAidl::write(const void *buffer, size_t bytes, size_t *written) {
492 if (buffer == nullptr || written == nullptr) {
493 return BAD_VALUE;
494 }
495 // For the output scenario, 'transfer' does not modify the buffer.
496 return transfer(const_cast<void*>(buffer), bytes, written);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000497}
498
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800499status_t StreamOutHalAidl::getRenderPosition(uint32_t *dspFrames) {
500 if (dspFrames == nullptr) {
501 return BAD_VALUE;
502 }
503 int64_t aidlFrames = 0, aidlTimestamp = 0;
504 if (status_t status = getObservablePosition(&aidlFrames, &aidlTimestamp); status != OK) {
505 return OK;
506 }
507 *dspFrames = std::clamp<int64_t>(aidlFrames, 0, UINT32_MAX);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000508 return OK;
509}
510
511status_t StreamOutHalAidl::getNextWriteTimestamp(int64_t *timestamp __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800512 // Obsolete, use getPresentationPosition.
513 return INVALID_OPERATION;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000514}
515
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800516status_t StreamOutHalAidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000517 TIME_CHECK();
518 if (!mStream) return NO_INIT;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800519 if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
520 if (auto cb = callback.promote(); cb != nullptr) {
521 broker->setStreamOutCallback(this, cb);
522 } else {
523 // It is expected that the framework never passes a null pointer.
524 // In the AIDL model callbacks can't be "unregistered".
525 LOG_ALWAYS_FATAL("%s: received an expired or null callback pointer", __func__);
526 }
527 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000528 return OK;
529}
530
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800531status_t StreamOutHalAidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
532 if (supportsPause == nullptr || supportsResume == nullptr) {
533 return BAD_VALUE;
534 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000535 TIME_CHECK();
536 if (!mStream) return NO_INIT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800537 *supportsPause = *supportsResume = true;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000538 return OK;
539}
540
541status_t StreamOutHalAidl::pause() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800542 return StreamHalAidl::pause();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000543}
544
545status_t StreamOutHalAidl::resume() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800546 return StreamHalAidl::resume();
547}
548
549status_t StreamOutHalAidl::supportsDrain(bool *supportsDrain) {
550 if (supportsDrain == nullptr) {
551 return BAD_VALUE;
552 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000553 TIME_CHECK();
554 if (!mStream) return NO_INIT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800555 *supportsDrain = true;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000556 return OK;
557}
558
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800559status_t StreamOutHalAidl::drain(bool earlyNotify) {
560 return StreamHalAidl::drain(earlyNotify);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000561}
562
563status_t StreamOutHalAidl::flush() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800564 return StreamHalAidl::flush();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000565}
566
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800567status_t StreamOutHalAidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
568 if (frames == nullptr || timestamp == nullptr) {
569 return BAD_VALUE;
570 }
571 int64_t aidlFrames = 0, aidlTimestamp = 0;
572 if (status_t status = getObservablePosition(&aidlFrames, &aidlTimestamp); status != OK) {
573 return status;
574 }
575 *frames = std::max<int64_t>(0, aidlFrames);
576 timestamp->tv_sec = aidlTimestamp / NANOS_PER_SECOND;
577 timestamp->tv_nsec = aidlTimestamp - timestamp->tv_sec * NANOS_PER_SECOND;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000578 return OK;
579}
580
581status_t StreamOutHalAidl::updateSourceMetadata(
582 const StreamOutHalInterface::SourceMetadata& sourceMetadata __unused) {
583 TIME_CHECK();
584 if (!mStream) return NO_INIT;
585 ALOGE("%s not implemented yet", __func__);
586 return OK;
587}
588
589status_t StreamOutHalAidl::getDualMonoMode(audio_dual_mono_mode_t* mode __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800590 TIME_CHECK();
591 if (!mStream) return NO_INIT;
592 ALOGE("%s not implemented yet", __func__);
593 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000594}
595
596status_t StreamOutHalAidl::setDualMonoMode(audio_dual_mono_mode_t mode __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800597 TIME_CHECK();
598 if (!mStream) return NO_INIT;
599 ALOGE("%s not implemented yet", __func__);
600 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000601}
602
603status_t StreamOutHalAidl::getAudioDescriptionMixLevel(float* leveldB __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800604 TIME_CHECK();
605 if (!mStream) return NO_INIT;
606 ALOGE("%s not implemented yet", __func__);
607 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000608}
609
610status_t StreamOutHalAidl::setAudioDescriptionMixLevel(float leveldB __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800611 TIME_CHECK();
612 if (!mStream) return NO_INIT;
613 ALOGE("%s not implemented yet", __func__);
614 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000615}
616
617status_t StreamOutHalAidl::getPlaybackRateParameters(
618 audio_playback_rate_t* playbackRate __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800619 TIME_CHECK();
620 if (!mStream) return NO_INIT;
621 ALOGE("%s not implemented yet", __func__);
David Lia6fb5752023-02-23 15:32:47 +0000622 return BAD_VALUE;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000623}
624
625status_t StreamOutHalAidl::setPlaybackRateParameters(
626 const audio_playback_rate_t& playbackRate __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800627 TIME_CHECK();
628 if (!mStream) return NO_INIT;
629 ALOGE("%s not implemented yet", __func__);
David Lia6fb5752023-02-23 15:32:47 +0000630 return BAD_VALUE;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000631}
632
633status_t StreamOutHalAidl::setEventCallback(
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800634 const sp<StreamOutHalInterfaceEventCallback>& callback) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800635 TIME_CHECK();
636 if (!mStream) return NO_INIT;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800637 if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
638 broker->setStreamOutEventCallback(this, callback);
639 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800640 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000641}
642
Mikhail Naganov31d46652023-01-10 18:29:25 +0000643status_t StreamOutHalAidl::setLatencyMode(audio_latency_mode_t mode __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800644 TIME_CHECK();
645 if (!mStream) return NO_INIT;
646 ALOGE("%s not implemented yet", __func__);
647 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000648};
649
650status_t StreamOutHalAidl::getRecommendedLatencyModes(
651 std::vector<audio_latency_mode_t> *modes __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800652 TIME_CHECK();
653 if (!mStream) return NO_INIT;
654 ALOGE("%s not implemented yet", __func__);
655 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000656};
657
658status_t StreamOutHalAidl::setLatencyModeCallback(
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800659 const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800660 TIME_CHECK();
661 if (!mStream) return NO_INIT;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800662 if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
663 broker->setStreamOutLatencyModeCallback(this, callback);
664 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800665 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000666};
667
Mikhail Naganov31d46652023-01-10 18:29:25 +0000668status_t StreamOutHalAidl::exit() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800669 return StreamHalAidl::exit();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000670}
671
672StreamInHalAidl::StreamInHalAidl(
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800673 const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
674 const std::shared_ptr<IStreamIn>& stream)
675 : StreamHalAidl("StreamInHalAidl", true /*isInput*/, config, nominalLatency,
676 std::move(context), getStreamCommon(stream)),
Mikhail Naganov31d46652023-01-10 18:29:25 +0000677 mStream(stream) {}
678
679status_t StreamInHalAidl::setGain(float gain __unused) {
680 TIME_CHECK();
681 if (!mStream) return NO_INIT;
682 ALOGE("%s not implemented yet", __func__);
683 return OK;
684}
685
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800686status_t StreamInHalAidl::read(void *buffer, size_t bytes, size_t *read) {
687 if (buffer == nullptr || read == nullptr) {
688 return BAD_VALUE;
689 }
690 return transfer(buffer, bytes, read);
691}
692
693status_t StreamInHalAidl::getInputFramesLost(uint32_t *framesLost) {
694 if (framesLost == nullptr) {
695 return BAD_VALUE;
696 }
697 int32_t aidlXruns = 0;
698 if (status_t status = getXruns(&aidlXruns); status != OK) {
699 return status;
700 }
701 *framesLost = std::max<int32_t>(0, aidlXruns);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000702 return OK;
703}
704
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800705status_t StreamInHalAidl::getCapturePosition(int64_t *frames, int64_t *time) {
706 if (frames == nullptr || time == nullptr) {
707 return BAD_VALUE;
708 }
709 return getObservablePosition(frames, time);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000710}
711
712status_t StreamInHalAidl::getActiveMicrophones(
Mikhail Naganov2a6a3012023-02-13 11:45:03 -0800713 std::vector<media::MicrophoneInfoFw> *microphones __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800714 TIME_CHECK();
715 if (!mStream) return NO_INIT;
716 ALOGE("%s not implemented yet", __func__);
717 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000718}
719
720status_t StreamInHalAidl::updateSinkMetadata(
721 const StreamInHalInterface::SinkMetadata& sinkMetadata __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800722 TIME_CHECK();
723 if (!mStream) return NO_INIT;
724 ALOGE("%s not implemented yet", __func__);
725 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000726}
727
728status_t StreamInHalAidl::setPreferredMicrophoneDirection(
729 audio_microphone_direction_t direction __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800730 TIME_CHECK();
731 if (!mStream) return NO_INIT;
732 ALOGE("%s not implemented yet", __func__);
733 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000734}
735
736status_t StreamInHalAidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800737 TIME_CHECK();
738 if (!mStream) return NO_INIT;
739 ALOGE("%s not implemented yet", __func__);
740 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000741}
742
743} // namespace android