blob: 2b85f97a28fea45ef4fa7c27af8a8dbc67ac4859 [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 Naganov31d46652023-01-10 18:29:25 +000023#include <aidl/android/hardware/audio/core/BnStreamCallback.h>
Mikhail Naganov89a9f742023-01-30 12:33:18 -080024#include <audio_utils/clock.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
31using ::aidl::android::hardware::audio::core::IStreamCommon;
32using ::aidl::android::hardware::audio::core::IStreamIn;
33using ::aidl::android::hardware::audio::core::IStreamOut;
34using ::aidl::android::hardware::audio::core::StreamDescriptor;
35
36namespace android {
37
Mikhail Naganov89a9f742023-01-30 12:33:18 -080038using HalCommand = StreamDescriptor::Command;
39namespace {
40template<HalCommand::Tag cmd> HalCommand makeHalCommand() {
41 return HalCommand::make<cmd>(::aidl::android::media::audio::common::Void{});
42}
43template<HalCommand::Tag cmd, typename T> HalCommand makeHalCommand(T data) {
44 return HalCommand::make<cmd>(data);
45}
46} // namespace
47
Mikhail Naganovfab697c2023-01-11 19:33:13 +000048// static
49template<class T>
50std::shared_ptr<IStreamCommon> StreamHalAidl::getStreamCommon(const std::shared_ptr<T>& stream) {
51 std::shared_ptr<::aidl::android::hardware::audio::core::IStreamCommon> streamCommon;
52 if (stream != nullptr) {
53 if (ndk::ScopedAStatus status = stream->getStreamCommon(&streamCommon);
54 !status.isOk()) {
55 ALOGE("%s: failed to retrieve IStreamCommon instance: %s", __func__,
56 status.getDescription().c_str());
57 }
58 }
59 return streamCommon;
60}
61
Mikhail Naganov31d46652023-01-10 18:29:25 +000062StreamHalAidl::StreamHalAidl(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080063 std::string_view className, bool isInput, const audio_config& config,
Mikhail Naganov89a9f742023-01-30 12:33:18 -080064 int32_t nominalLatency, StreamContextAidl&& context,
65 const std::shared_ptr<IStreamCommon>& stream)
Mikhail Naganov31d46652023-01-10 18:29:25 +000066 : ConversionHelperAidl(className),
67 mIsInput(isInput),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080068 mConfig(configToBase(config)),
Mikhail Naganov89a9f742023-01-30 12:33:18 -080069 mContext(std::move(context)),
Mikhail Naganov31d46652023-01-10 18:29:25 +000070 mStream(stream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -080071 {
72 std::lock_guard l(mLock);
73 mLastReply.latencyMs = nominalLatency;
74 }
Mikhail Naganov31d46652023-01-10 18:29:25 +000075 // Instrument audio signal power logging.
76 // Note: This assumes channel mask, format, and sample rate do not change after creation.
77 if (audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
78 /* mStreamPowerLog.isUserDebugOrEngBuild() && */
79 StreamHalAidl::getAudioProperties(&config) == NO_ERROR) {
80 mStreamPowerLog.init(config.sample_rate, config.channel_mask, config.format);
81 }
82}
83
84StreamHalAidl::~StreamHalAidl() {
85 if (mStream != nullptr) {
86 ndk::ScopedAStatus status = mStream->close();
87 ALOGE_IF(!status.isOk(), "%s: status %s", __func__, status.getDescription().c_str());
88 }
89}
90
91status_t StreamHalAidl::getBufferSize(size_t *size) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -080092 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +000093 if (size == nullptr) {
94 return BAD_VALUE;
95 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -080096 if (mContext.getFrameSizeBytes() == 0 || mContext.getBufferSizeFrames() == 0 ||
97 !mStream) {
Mikhail Naganov31d46652023-01-10 18:29:25 +000098 return NO_INIT;
99 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800100 *size = mContext.getBufferSizeBytes();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000101 return OK;
102}
103
104status_t StreamHalAidl::getAudioProperties(audio_config_base_t *configBase) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800105 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000106 if (configBase == nullptr) {
107 return BAD_VALUE;
108 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800109 if (!mStream) return NO_INIT;
110 *configBase = mConfig;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000111 return OK;
112}
113
114status_t StreamHalAidl::setParameters(const String8& kvPairs __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800115 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000116 TIME_CHECK();
117 if (!mStream) return NO_INIT;
118 ALOGE("%s not implemented yet", __func__);
119 return OK;
120}
121
122status_t StreamHalAidl::getParameters(const String8& keys __unused, String8 *values) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800123 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000124 TIME_CHECK();
125 values->clear();
126 if (!mStream) return NO_INIT;
127 ALOGE("%s not implemented yet", __func__);
128 return OK;
129}
130
131status_t StreamHalAidl::getFrameSize(size_t *size) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800132 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000133 if (size == nullptr) {
134 return BAD_VALUE;
135 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800136 if (mContext.getFrameSizeBytes() == 0 || !mStream) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000137 return NO_INIT;
138 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800139 *size = mContext.getFrameSizeBytes();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000140 return OK;
141}
142
143status_t StreamHalAidl::addEffect(sp<EffectHalInterface> effect __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800144 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000145 TIME_CHECK();
146 if (!mStream) return NO_INIT;
147 ALOGE("%s not implemented yet", __func__);
148 return OK;
149}
150
151status_t StreamHalAidl::removeEffect(sp<EffectHalInterface> effect __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800152 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000153 TIME_CHECK();
154 if (!mStream) return NO_INIT;
155 ALOGE("%s not implemented yet", __func__);
156 return OK;
157}
158
159status_t StreamHalAidl::standby() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800160 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000161 TIME_CHECK();
162 if (!mStream) return NO_INIT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800163 const auto state = getState();
164 StreamDescriptor::Reply reply;
165 switch (state) {
166 case StreamDescriptor::State::ACTIVE:
167 if (status_t status = pause(&reply); status != OK) return status;
168 if (reply.state != StreamDescriptor::State::PAUSED) {
169 ALOGE("%s: unexpected stream state: %s (expected PAUSED)",
170 __func__, toString(reply.state).c_str());
171 return INVALID_OPERATION;
172 }
173 FALLTHROUGH_INTENDED;
174 case StreamDescriptor::State::PAUSED:
175 case StreamDescriptor::State::DRAIN_PAUSED:
176 return flush();
177 case StreamDescriptor::State::IDLE:
178 if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::standby>(),
179 &reply); status != OK) {
180 return status;
181 }
182 if (reply.state != StreamDescriptor::State::STANDBY) {
183 ALOGE("%s: unexpected stream state: %s (expected STANDBY)",
184 __func__, toString(reply.state).c_str());
185 return INVALID_OPERATION;
186 }
187 FALLTHROUGH_INTENDED;
188 case StreamDescriptor::State::STANDBY:
189 return OK;
190 default:
191 ALOGE("%s: not supported from %s stream state %s",
192 __func__, mIsInput ? "input" : "output", toString(state).c_str());
193 return INVALID_OPERATION;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800194 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000195}
196
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000197status_t StreamHalAidl::dump(int fd, const Vector<String16>& args) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800198 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000199 TIME_CHECK();
200 if (!mStream) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000201 return mStream->dump(fd, Args(args).args(), args.size());
Mikhail Naganov31d46652023-01-10 18:29:25 +0000202}
203
204status_t StreamHalAidl::start() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800205 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000206 TIME_CHECK();
207 if (!mStream) return NO_INIT;
208 ALOGE("%s not implemented yet", __func__);
209 return OK;
210}
211
212status_t StreamHalAidl::stop() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800213 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
214 TIME_CHECK();
215 if (!mStream) return NO_INIT;
216 ALOGE("%s not implemented yet", __func__);
217 return OK;
218}
219
220status_t StreamHalAidl::getLatency(uint32_t *latency) {
221 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
222 if (!mStream) return NO_INIT;
223 StreamDescriptor::Reply reply;
224 if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
225 return status;
226 }
227 *latency = std::max<int32_t>(0, reply.latencyMs);
228 return OK;
229}
230
231status_t StreamHalAidl::getObservablePosition(int64_t *frames, int64_t *timestamp) {
232 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
233 if (!mStream) return NO_INIT;
234 StreamDescriptor::Reply reply;
235 if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
236 return status;
237 }
238 *frames = reply.observable.frames;
239 *timestamp = reply.observable.timeNs;
240 return OK;
241}
242
243status_t StreamHalAidl::getXruns(int32_t *frames) {
244 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
245 if (!mStream) return NO_INIT;
246 StreamDescriptor::Reply reply;
247 if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
248 return status;
249 }
250 *frames = reply.xrunFrames;
251 return OK;
252}
253
254status_t StreamHalAidl::transfer(void *buffer, size_t bytes, size_t *transferred) {
255 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
256 // TIME_CHECK(); // TODO(b/238654698) reenable only when optimized.
257 if (!mStream || mContext.getDataMQ() == nullptr) return NO_INIT;
258 mWorkerTid.store(gettid(), std::memory_order_release);
259 // Switch the stream into an active state if needed.
260 // Note: in future we may add support for priming the audio pipeline
261 // with data prior to enabling output (thus we can issue a "burst" command in the "standby"
262 // stream state), however this scenario wasn't supported by the HIDL HAL.
263 if (getState() == StreamDescriptor::State::STANDBY) {
264 StreamDescriptor::Reply reply;
265 if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply);
266 status != OK) {
267 return status;
268 }
269 if (reply.state != StreamDescriptor::State::IDLE) {
270 ALOGE("%s: failed to get the stream out of standby, actual state: %s",
271 __func__, toString(reply.state).c_str());
272 return INVALID_OPERATION;
273 }
274 }
275 if (!mIsInput) {
276 bytes = std::min(bytes, mContext.getDataMQ()->availableToWrite());
277 }
278 StreamDescriptor::Command burst =
279 StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(bytes);
280 if (!mIsInput) {
281 if (!mContext.getDataMQ()->write(static_cast<const int8_t*>(buffer), bytes)) {
282 ALOGE("%s: failed to write %zu bytes to data MQ", __func__, bytes);
283 return NOT_ENOUGH_DATA;
284 }
285 }
286 StreamDescriptor::Reply reply;
287 if (status_t status = sendCommand(burst, &reply); status != OK) {
288 return status;
289 }
290 if (mIsInput) {
291 *transferred = reply.fmqByteCount;
292 LOG_ALWAYS_FATAL_IF(*transferred > bytes,
293 "%s: HAL module read %zu bytes, which exceeds requested count %zu",
294 __func__, *transferred, bytes);
295 if (!mContext.getDataMQ()->read(static_cast<int8_t*>(buffer), *transferred)) {
296 ALOGE("%s: failed to read %zu bytes to data MQ", __func__, *transferred);
297 return NOT_ENOUGH_DATA;
298 }
299 }
300 mStreamPowerLog.log(buffer, *transferred);
301 return OK;
302}
303
304status_t StreamHalAidl::pause(StreamDescriptor::Reply* reply) {
305 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
306 TIME_CHECK();
307 if (!mStream) return NO_INIT;
308 return sendCommand(makeHalCommand<HalCommand::Tag::pause>(), reply,
309 true /*safeFromNonWorkerThread*/); // The workers stops its I/O activity first.
310}
311
312status_t StreamHalAidl::resume(StreamDescriptor::Reply* reply) {
313 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
314 TIME_CHECK();
315 if (!mStream) return NO_INIT;
316 if (mIsInput) {
317 return sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), reply);
318 } else {
319 return sendCommand(makeHalCommand<HalCommand::Tag::start>(), reply);
320 }
321}
322
323status_t StreamHalAidl::drain(bool earlyNotify, StreamDescriptor::Reply* reply) {
324 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
325 TIME_CHECK();
326 if (!mStream) return NO_INIT;
327 return sendCommand(makeHalCommand<HalCommand::Tag::drain>(
328 mIsInput ? StreamDescriptor::DrainMode::DRAIN_UNSPECIFIED :
329 earlyNotify ? StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY :
330 StreamDescriptor::DrainMode::DRAIN_ALL), reply);
331}
332
333status_t StreamHalAidl::flush(StreamDescriptor::Reply* reply) {
334 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
335 TIME_CHECK();
336 if (!mStream) return NO_INIT;
337 return sendCommand(makeHalCommand<HalCommand::Tag::flush>(), reply,
338 true /*safeFromNonWorkerThread*/); // The workers stops its I/O activity first.
339}
340
341status_t StreamHalAidl::exit() {
342 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000343 TIME_CHECK();
344 if (!mStream) return NO_INIT;
345 ALOGE("%s not implemented yet", __func__);
346 return OK;
347}
348
349status_t StreamHalAidl::createMmapBuffer(int32_t minSizeFrames __unused,
350 struct audio_mmap_buffer_info *info __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800351 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000352 TIME_CHECK();
353 if (!mStream) return NO_INIT;
354 ALOGE("%s not implemented yet", __func__);
355 return OK;
356}
357
358status_t StreamHalAidl::getMmapPosition(struct audio_mmap_position *position __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800359 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000360 TIME_CHECK();
361 if (!mStream) return NO_INIT;
362 ALOGE("%s not implemented yet", __func__);
363 return OK;
364}
365
366status_t StreamHalAidl::setHalThreadPriority(int priority __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800367 // Obsolete, must be done by the HAL module.
Mikhail Naganov31d46652023-01-10 18:29:25 +0000368 return OK;
369}
370
371status_t StreamHalAidl::getHalPid(pid_t *pid __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800372 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000373 TIME_CHECK();
374 if (!mStream) return NO_INIT;
375 ALOGE("%s not implemented yet", __func__);
376 return OK;
377}
378
379bool StreamHalAidl::requestHalThreadPriority(pid_t threadPid __unused, pid_t threadId __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800380 // Obsolete, must be done by the HAL module.
381 return true;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000382}
383
384status_t StreamHalAidl::legacyCreateAudioPatch(const struct audio_port_config& port __unused,
385 std::optional<audio_source_t> source __unused,
386 audio_devices_t type __unused) {
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000387 // Obsolete since 'DeviceHalAidl.supportsAudioPatches' always returns 'true'.
388 return INVALID_OPERATION;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000389}
390
391status_t StreamHalAidl::legacyReleaseAudioPatch() {
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000392 // Obsolete since 'DeviceHalAidl.supportsAudioPatches' always returns 'true'.
393 return INVALID_OPERATION;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000394}
395
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800396status_t StreamHalAidl::sendCommand(
397 const ::aidl::android::hardware::audio::core::StreamDescriptor::Command &command,
398 ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply,
399 bool safeFromNonWorkerThread) {
400 // TIME_CHECK(); // TODO(b/238654698) reenable only when optimized.
401 if (!safeFromNonWorkerThread) {
402 const pid_t workerTid = mWorkerTid.load(std::memory_order_acquire);
403 LOG_ALWAYS_FATAL_IF(workerTid != gettid(),
404 "%s %s: must be invoked from the worker thread (%d)",
405 __func__, command.toString().c_str(), workerTid);
406 }
407 if (!mContext.getCommandMQ()->writeBlocking(&command, 1)) {
408 ALOGE("%s: failed to write command %s to MQ", __func__, command.toString().c_str());
409 return NOT_ENOUGH_DATA;
410 }
411 StreamDescriptor::Reply localReply{};
412 if (reply == nullptr) {
413 reply = &localReply;
414 }
415 if (!mContext.getReplyMQ()->readBlocking(reply, 1)) {
416 ALOGE("%s: failed to read from reply MQ, command %s", __func__, command.toString().c_str());
417 return NOT_ENOUGH_DATA;
418 }
419 {
420 std::lock_guard l(mLock);
421 mLastReply = *reply;
422 }
423 switch (reply->status) {
424 case STATUS_OK: return OK;
425 case STATUS_BAD_VALUE: return BAD_VALUE;
426 case STATUS_INVALID_OPERATION: return INVALID_OPERATION;
427 case STATUS_NOT_ENOUGH_DATA: return NOT_ENOUGH_DATA;
428 default:
429 ALOGE("%s: unexpected status %d returned for command %s",
430 __func__, reply->status, command.toString().c_str());
431 return INVALID_OPERATION;
432 }
433}
434
435status_t StreamHalAidl::updateCountersIfNeeded(
436 ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply) {
437 if (mWorkerTid.load(std::memory_order_acquire) == gettid()) {
438 if (const auto state = getState(); state != StreamDescriptor::State::ACTIVE &&
439 state != StreamDescriptor::State::DRAINING &&
440 state != StreamDescriptor::State::TRANSFERRING) {
441 return sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), reply);
442 }
443 }
444 if (reply != nullptr) {
445 std::lock_guard l(mLock);
446 *reply = mLastReply;
447 }
448 return OK;
449}
450
Mikhail Naganov31d46652023-01-10 18:29:25 +0000451namespace {
452
453/* Notes on callback ownership.
454
455This is how Binder ownership model looks like. The server implementation
456is owned by Binder framework (via sp<>). Proxies are owned by clients.
457When the last proxy disappears, Binder framework releases the server impl.
458
459Thus, it is not needed to keep any references to StreamCallback (this is
460the server impl) -- it will live as long as HAL server holds a strong ref to
461IStreamCallback proxy.
462
463The callback only keeps a weak reference to the stream. The stream is owned
464by AudioFlinger.
465
466*/
467
468class StreamCallback : public ::aidl::android::hardware::audio::core::BnStreamCallback {
469 ndk::ScopedAStatus onTransferReady() override {
470 return ndk::ScopedAStatus::ok();
471 }
472 ndk::ScopedAStatus onError() override {
473 return ndk::ScopedAStatus::ok();
474 }
475 ndk::ScopedAStatus onDrainReady() override {
476 return ndk::ScopedAStatus::ok();
477 }
478};
479
480} // namespace
481
482StreamOutHalAidl::StreamOutHalAidl(
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800483 const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
484 const std::shared_ptr<IStreamOut>& stream)
485 : StreamHalAidl("StreamOutHalAidl", false /*isInput*/, config, nominalLatency,
486 std::move(context), getStreamCommon(stream)),
Mikhail Naganov31d46652023-01-10 18:29:25 +0000487 mStream(stream) {}
488
489status_t StreamOutHalAidl::getLatency(uint32_t *latency) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800490 return StreamHalAidl::getLatency(latency);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000491}
492
493status_t StreamOutHalAidl::setVolume(float left __unused, float right __unused) {
494 TIME_CHECK();
495 if (!mStream) return NO_INIT;
496 ALOGE("%s not implemented yet", __func__);
497 return OK;
498}
499
500status_t StreamOutHalAidl::selectPresentation(int presentationId __unused, int programId __unused) {
501 TIME_CHECK();
502 if (!mStream) return NO_INIT;
503 ALOGE("%s not implemented yet", __func__);
504 return OK;
505}
506
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800507status_t StreamOutHalAidl::write(const void *buffer, size_t bytes, size_t *written) {
508 if (buffer == nullptr || written == nullptr) {
509 return BAD_VALUE;
510 }
511 // For the output scenario, 'transfer' does not modify the buffer.
512 return transfer(const_cast<void*>(buffer), bytes, written);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000513}
514
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800515status_t StreamOutHalAidl::getRenderPosition(uint32_t *dspFrames) {
516 if (dspFrames == nullptr) {
517 return BAD_VALUE;
518 }
519 int64_t aidlFrames = 0, aidlTimestamp = 0;
520 if (status_t status = getObservablePosition(&aidlFrames, &aidlTimestamp); status != OK) {
521 return OK;
522 }
523 *dspFrames = std::clamp<int64_t>(aidlFrames, 0, UINT32_MAX);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000524 return OK;
525}
526
527status_t StreamOutHalAidl::getNextWriteTimestamp(int64_t *timestamp __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800528 // Obsolete, use getPresentationPosition.
529 return INVALID_OPERATION;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000530}
531
532status_t StreamOutHalAidl::setCallback(wp<StreamOutHalInterfaceCallback> callback __unused) {
533 TIME_CHECK();
534 if (!mStream) return NO_INIT;
535 ALOGE("%s not implemented yet", __func__);
536 return OK;
537}
538
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800539status_t StreamOutHalAidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
540 if (supportsPause == nullptr || supportsResume == nullptr) {
541 return BAD_VALUE;
542 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000543 TIME_CHECK();
544 if (!mStream) return NO_INIT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800545 *supportsPause = *supportsResume = true;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000546 return OK;
547}
548
549status_t StreamOutHalAidl::pause() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800550 return StreamHalAidl::pause();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000551}
552
553status_t StreamOutHalAidl::resume() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800554 return StreamHalAidl::resume();
555}
556
557status_t StreamOutHalAidl::supportsDrain(bool *supportsDrain) {
558 if (supportsDrain == nullptr) {
559 return BAD_VALUE;
560 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000561 TIME_CHECK();
562 if (!mStream) return NO_INIT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800563 *supportsDrain = true;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000564 return OK;
565}
566
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800567status_t StreamOutHalAidl::drain(bool earlyNotify) {
568 return StreamHalAidl::drain(earlyNotify);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000569}
570
571status_t StreamOutHalAidl::flush() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800572 return StreamHalAidl::flush();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000573}
574
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800575status_t StreamOutHalAidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
576 if (frames == nullptr || timestamp == nullptr) {
577 return BAD_VALUE;
578 }
579 int64_t aidlFrames = 0, aidlTimestamp = 0;
580 if (status_t status = getObservablePosition(&aidlFrames, &aidlTimestamp); status != OK) {
581 return status;
582 }
583 *frames = std::max<int64_t>(0, aidlFrames);
584 timestamp->tv_sec = aidlTimestamp / NANOS_PER_SECOND;
585 timestamp->tv_nsec = aidlTimestamp - timestamp->tv_sec * NANOS_PER_SECOND;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000586 return OK;
587}
588
589status_t StreamOutHalAidl::updateSourceMetadata(
590 const StreamOutHalInterface::SourceMetadata& sourceMetadata __unused) {
591 TIME_CHECK();
592 if (!mStream) return NO_INIT;
593 ALOGE("%s not implemented yet", __func__);
594 return OK;
595}
596
597status_t StreamOutHalAidl::getDualMonoMode(audio_dual_mono_mode_t* mode __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800598 TIME_CHECK();
599 if (!mStream) return NO_INIT;
600 ALOGE("%s not implemented yet", __func__);
601 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000602}
603
604status_t StreamOutHalAidl::setDualMonoMode(audio_dual_mono_mode_t mode __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800605 TIME_CHECK();
606 if (!mStream) return NO_INIT;
607 ALOGE("%s not implemented yet", __func__);
608 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000609}
610
611status_t StreamOutHalAidl::getAudioDescriptionMixLevel(float* leveldB __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800612 TIME_CHECK();
613 if (!mStream) return NO_INIT;
614 ALOGE("%s not implemented yet", __func__);
615 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000616}
617
618status_t StreamOutHalAidl::setAudioDescriptionMixLevel(float leveldB __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800619 TIME_CHECK();
620 if (!mStream) return NO_INIT;
621 ALOGE("%s not implemented yet", __func__);
622 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000623}
624
625status_t StreamOutHalAidl::getPlaybackRateParameters(
626 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__);
630 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000631}
632
633status_t StreamOutHalAidl::setPlaybackRateParameters(
634 const audio_playback_rate_t& playbackRate __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800635 TIME_CHECK();
636 if (!mStream) return NO_INIT;
637 ALOGE("%s not implemented yet", __func__);
638 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000639}
640
641status_t StreamOutHalAidl::setEventCallback(
642 const sp<StreamOutHalInterfaceEventCallback>& callback __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800643 TIME_CHECK();
644 if (!mStream) return NO_INIT;
645 ALOGE("%s not implemented yet", __func__);
646 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000647}
648
649namespace {
650
651struct StreamOutEventCallback {
652 StreamOutEventCallback(const wp<StreamOutHalAidl>& stream) : mStream(stream) {}
653 private:
654 wp<StreamOutHalAidl> mStream;
655};
656
657} // namespace
658
659status_t StreamOutHalAidl::setLatencyMode(audio_latency_mode_t mode __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800660 TIME_CHECK();
661 if (!mStream) return NO_INIT;
662 ALOGE("%s not implemented yet", __func__);
663 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000664};
665
666status_t StreamOutHalAidl::getRecommendedLatencyModes(
667 std::vector<audio_latency_mode_t> *modes __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800668 TIME_CHECK();
669 if (!mStream) return NO_INIT;
670 ALOGE("%s not implemented yet", __func__);
671 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000672};
673
674status_t StreamOutHalAidl::setLatencyModeCallback(
675 const sp<StreamOutHalInterfaceLatencyModeCallback>& callback __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800676 TIME_CHECK();
677 if (!mStream) return NO_INIT;
678 ALOGE("%s not implemented yet", __func__);
679 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000680};
681
682void StreamOutHalAidl::onWriteReady() {
683 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
684 if (callback == 0) return;
685 ALOGV("asyncCallback onWriteReady");
686 callback->onWriteReady();
687}
688
689void StreamOutHalAidl::onDrainReady() {
690 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
691 if (callback == 0) return;
692 ALOGV("asyncCallback onDrainReady");
693 callback->onDrainReady();
694}
695
696void StreamOutHalAidl::onError() {
697 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
698 if (callback == 0) return;
699 ALOGV("asyncCallback onError");
700 callback->onError();
701}
702
703void StreamOutHalAidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs __unused) {
704 sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.load().promote();
705 if (callback == nullptr) return;
706 ALOGV("asyncCodecFormatCallback %s", __func__);
707 callback->onCodecFormatChanged(metadataBs);
708}
709
710void StreamOutHalAidl::onRecommendedLatencyModeChanged(
711 const std::vector<audio_latency_mode_t>& modes __unused) {
712 sp<StreamOutHalInterfaceLatencyModeCallback> callback = mLatencyModeCallback.load().promote();
713 if (callback == nullptr) return;
714 callback->onRecommendedLatencyModeChanged(modes);
715}
716
717status_t StreamOutHalAidl::exit() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800718 return StreamHalAidl::exit();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000719}
720
721StreamInHalAidl::StreamInHalAidl(
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800722 const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
723 const std::shared_ptr<IStreamIn>& stream)
724 : StreamHalAidl("StreamInHalAidl", true /*isInput*/, config, nominalLatency,
725 std::move(context), getStreamCommon(stream)),
Mikhail Naganov31d46652023-01-10 18:29:25 +0000726 mStream(stream) {}
727
728status_t StreamInHalAidl::setGain(float gain __unused) {
729 TIME_CHECK();
730 if (!mStream) return NO_INIT;
731 ALOGE("%s not implemented yet", __func__);
732 return OK;
733}
734
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800735status_t StreamInHalAidl::read(void *buffer, size_t bytes, size_t *read) {
736 if (buffer == nullptr || read == nullptr) {
737 return BAD_VALUE;
738 }
739 return transfer(buffer, bytes, read);
740}
741
742status_t StreamInHalAidl::getInputFramesLost(uint32_t *framesLost) {
743 if (framesLost == nullptr) {
744 return BAD_VALUE;
745 }
746 int32_t aidlXruns = 0;
747 if (status_t status = getXruns(&aidlXruns); status != OK) {
748 return status;
749 }
750 *framesLost = std::max<int32_t>(0, aidlXruns);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000751 return OK;
752}
753
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800754status_t StreamInHalAidl::getCapturePosition(int64_t *frames, int64_t *time) {
755 if (frames == nullptr || time == nullptr) {
756 return BAD_VALUE;
757 }
758 return getObservablePosition(frames, time);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000759}
760
761status_t StreamInHalAidl::getActiveMicrophones(
762 std::vector<media::MicrophoneInfo> *microphones __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800763 TIME_CHECK();
764 if (!mStream) return NO_INIT;
765 ALOGE("%s not implemented yet", __func__);
766 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000767}
768
769status_t StreamInHalAidl::updateSinkMetadata(
770 const StreamInHalInterface::SinkMetadata& sinkMetadata __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800771 TIME_CHECK();
772 if (!mStream) return NO_INIT;
773 ALOGE("%s not implemented yet", __func__);
774 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000775}
776
777status_t StreamInHalAidl::setPreferredMicrophoneDirection(
778 audio_microphone_direction_t direction __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800779 TIME_CHECK();
780 if (!mStream) return NO_INIT;
781 ALOGE("%s not implemented yet", __func__);
782 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000783}
784
785status_t StreamInHalAidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800786 TIME_CHECK();
787 if (!mStream) return NO_INIT;
788 ALOGE("%s not implemented yet", __func__);
789 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000790}
791
792} // namespace android