blob: a97bd02169ba447aa5c245fb2aa12589d1b0e7ba [file] [log] [blame]
Mikhail Naganov31d46652023-01-10 18:29:25 +00001/*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "StreamHalAidl"
18//#define LOG_NDEBUG 0
19
Mikhail Naganov89a9f742023-01-30 12:33:18 -080020#include <algorithm>
21#include <cstdint>
22
Mikhail Naganov89a9f742023-01-30 12:33:18 -080023#include <audio_utils/clock.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000024#include <mediautils/TimeCheck.h>
25#include <utils/Log.h>
26
27#include "DeviceHalAidl.h"
28#include "StreamHalAidl.h"
29
30using ::aidl::android::hardware::audio::core::IStreamCommon;
31using ::aidl::android::hardware::audio::core::IStreamIn;
32using ::aidl::android::hardware::audio::core::IStreamOut;
33using ::aidl::android::hardware::audio::core::StreamDescriptor;
34
35namespace android {
36
Mikhail Naganov89a9f742023-01-30 12:33:18 -080037using HalCommand = StreamDescriptor::Command;
38namespace {
39template<HalCommand::Tag cmd> HalCommand makeHalCommand() {
40 return HalCommand::make<cmd>(::aidl::android::media::audio::common::Void{});
41}
42template<HalCommand::Tag cmd, typename T> HalCommand makeHalCommand(T data) {
43 return HalCommand::make<cmd>(data);
44}
45} // namespace
46
Mikhail Naganovfab697c2023-01-11 19:33:13 +000047// static
48template<class T>
49std::shared_ptr<IStreamCommon> StreamHalAidl::getStreamCommon(const std::shared_ptr<T>& stream) {
50 std::shared_ptr<::aidl::android::hardware::audio::core::IStreamCommon> streamCommon;
51 if (stream != nullptr) {
52 if (ndk::ScopedAStatus status = stream->getStreamCommon(&streamCommon);
53 !status.isOk()) {
54 ALOGE("%s: failed to retrieve IStreamCommon instance: %s", __func__,
55 status.getDescription().c_str());
56 }
57 }
58 return streamCommon;
59}
60
Mikhail Naganov31d46652023-01-10 18:29:25 +000061StreamHalAidl::StreamHalAidl(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080062 std::string_view className, bool isInput, const audio_config& config,
Mikhail Naganov89a9f742023-01-30 12:33:18 -080063 int32_t nominalLatency, StreamContextAidl&& context,
64 const std::shared_ptr<IStreamCommon>& stream)
Mikhail Naganov31d46652023-01-10 18:29:25 +000065 : ConversionHelperAidl(className),
66 mIsInput(isInput),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080067 mConfig(configToBase(config)),
Mikhail Naganov89a9f742023-01-30 12:33:18 -080068 mContext(std::move(context)),
Mikhail Naganov31d46652023-01-10 18:29:25 +000069 mStream(stream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -080070 {
71 std::lock_guard l(mLock);
72 mLastReply.latencyMs = nominalLatency;
73 }
Mikhail Naganov31d46652023-01-10 18:29:25 +000074 // Instrument audio signal power logging.
75 // Note: This assumes channel mask, format, and sample rate do not change after creation.
76 if (audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
77 /* mStreamPowerLog.isUserDebugOrEngBuild() && */
78 StreamHalAidl::getAudioProperties(&config) == NO_ERROR) {
79 mStreamPowerLog.init(config.sample_rate, config.channel_mask, config.format);
80 }
81}
82
83StreamHalAidl::~StreamHalAidl() {
84 if (mStream != nullptr) {
85 ndk::ScopedAStatus status = mStream->close();
86 ALOGE_IF(!status.isOk(), "%s: status %s", __func__, status.getDescription().c_str());
87 }
88}
89
90status_t StreamHalAidl::getBufferSize(size_t *size) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -080091 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +000092 if (size == nullptr) {
93 return BAD_VALUE;
94 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -080095 if (mContext.getFrameSizeBytes() == 0 || mContext.getBufferSizeFrames() == 0 ||
96 !mStream) {
Mikhail Naganov31d46652023-01-10 18:29:25 +000097 return NO_INIT;
98 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -080099 *size = mContext.getBufferSizeBytes();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000100 return OK;
101}
102
103status_t StreamHalAidl::getAudioProperties(audio_config_base_t *configBase) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800104 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000105 if (configBase == nullptr) {
106 return BAD_VALUE;
107 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800108 if (!mStream) return NO_INIT;
109 *configBase = mConfig;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000110 return OK;
111}
112
113status_t StreamHalAidl::setParameters(const String8& kvPairs __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800114 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000115 TIME_CHECK();
116 if (!mStream) return NO_INIT;
117 ALOGE("%s not implemented yet", __func__);
118 return OK;
119}
120
121status_t StreamHalAidl::getParameters(const String8& keys __unused, String8 *values) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800122 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000123 TIME_CHECK();
124 values->clear();
125 if (!mStream) return NO_INIT;
126 ALOGE("%s not implemented yet", __func__);
127 return OK;
128}
129
130status_t StreamHalAidl::getFrameSize(size_t *size) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800131 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000132 if (size == nullptr) {
133 return BAD_VALUE;
134 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800135 if (mContext.getFrameSizeBytes() == 0 || !mStream) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000136 return NO_INIT;
137 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800138 *size = mContext.getFrameSizeBytes();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000139 return OK;
140}
141
142status_t StreamHalAidl::addEffect(sp<EffectHalInterface> effect __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800143 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000144 TIME_CHECK();
145 if (!mStream) return NO_INIT;
146 ALOGE("%s not implemented yet", __func__);
147 return OK;
148}
149
150status_t StreamHalAidl::removeEffect(sp<EffectHalInterface> effect __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800151 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000152 TIME_CHECK();
153 if (!mStream) return NO_INIT;
154 ALOGE("%s not implemented yet", __func__);
155 return OK;
156}
157
158status_t StreamHalAidl::standby() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800159 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000160 TIME_CHECK();
161 if (!mStream) return NO_INIT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800162 const auto state = getState();
163 StreamDescriptor::Reply reply;
164 switch (state) {
165 case StreamDescriptor::State::ACTIVE:
166 if (status_t status = pause(&reply); status != OK) return status;
167 if (reply.state != StreamDescriptor::State::PAUSED) {
168 ALOGE("%s: unexpected stream state: %s (expected PAUSED)",
169 __func__, toString(reply.state).c_str());
170 return INVALID_OPERATION;
171 }
172 FALLTHROUGH_INTENDED;
173 case StreamDescriptor::State::PAUSED:
174 case StreamDescriptor::State::DRAIN_PAUSED:
175 return flush();
176 case StreamDescriptor::State::IDLE:
177 if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::standby>(),
178 &reply); status != OK) {
179 return status;
180 }
181 if (reply.state != StreamDescriptor::State::STANDBY) {
182 ALOGE("%s: unexpected stream state: %s (expected STANDBY)",
183 __func__, toString(reply.state).c_str());
184 return INVALID_OPERATION;
185 }
186 FALLTHROUGH_INTENDED;
187 case StreamDescriptor::State::STANDBY:
188 return OK;
189 default:
190 ALOGE("%s: not supported from %s stream state %s",
191 __func__, mIsInput ? "input" : "output", toString(state).c_str());
192 return INVALID_OPERATION;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800193 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000194}
195
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000196status_t StreamHalAidl::dump(int fd, const Vector<String16>& args) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800197 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000198 TIME_CHECK();
199 if (!mStream) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000200 return mStream->dump(fd, Args(args).args(), args.size());
Mikhail Naganov31d46652023-01-10 18:29:25 +0000201}
202
203status_t StreamHalAidl::start() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800204 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000205 TIME_CHECK();
206 if (!mStream) return NO_INIT;
207 ALOGE("%s not implemented yet", __func__);
208 return OK;
209}
210
211status_t StreamHalAidl::stop() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800212 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
213 TIME_CHECK();
214 if (!mStream) return NO_INIT;
215 ALOGE("%s not implemented yet", __func__);
216 return OK;
217}
218
219status_t StreamHalAidl::getLatency(uint32_t *latency) {
220 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
221 if (!mStream) return NO_INIT;
222 StreamDescriptor::Reply reply;
223 if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
224 return status;
225 }
226 *latency = std::max<int32_t>(0, reply.latencyMs);
227 return OK;
228}
229
230status_t StreamHalAidl::getObservablePosition(int64_t *frames, int64_t *timestamp) {
231 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
232 if (!mStream) return NO_INIT;
233 StreamDescriptor::Reply reply;
234 if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
235 return status;
236 }
237 *frames = reply.observable.frames;
238 *timestamp = reply.observable.timeNs;
239 return OK;
240}
241
242status_t StreamHalAidl::getXruns(int32_t *frames) {
243 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
244 if (!mStream) return NO_INIT;
245 StreamDescriptor::Reply reply;
246 if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
247 return status;
248 }
249 *frames = reply.xrunFrames;
250 return OK;
251}
252
253status_t StreamHalAidl::transfer(void *buffer, size_t bytes, size_t *transferred) {
254 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
255 // TIME_CHECK(); // TODO(b/238654698) reenable only when optimized.
256 if (!mStream || mContext.getDataMQ() == nullptr) return NO_INIT;
257 mWorkerTid.store(gettid(), std::memory_order_release);
258 // Switch the stream into an active state if needed.
259 // Note: in future we may add support for priming the audio pipeline
260 // with data prior to enabling output (thus we can issue a "burst" command in the "standby"
261 // stream state), however this scenario wasn't supported by the HIDL HAL.
262 if (getState() == StreamDescriptor::State::STANDBY) {
263 StreamDescriptor::Reply reply;
264 if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply);
265 status != OK) {
266 return status;
267 }
268 if (reply.state != StreamDescriptor::State::IDLE) {
269 ALOGE("%s: failed to get the stream out of standby, actual state: %s",
270 __func__, toString(reply.state).c_str());
271 return INVALID_OPERATION;
272 }
273 }
274 if (!mIsInput) {
275 bytes = std::min(bytes, mContext.getDataMQ()->availableToWrite());
276 }
277 StreamDescriptor::Command burst =
278 StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(bytes);
279 if (!mIsInput) {
280 if (!mContext.getDataMQ()->write(static_cast<const int8_t*>(buffer), bytes)) {
281 ALOGE("%s: failed to write %zu bytes to data MQ", __func__, bytes);
282 return NOT_ENOUGH_DATA;
283 }
284 }
285 StreamDescriptor::Reply reply;
286 if (status_t status = sendCommand(burst, &reply); status != OK) {
287 return status;
288 }
289 if (mIsInput) {
290 *transferred = reply.fmqByteCount;
291 LOG_ALWAYS_FATAL_IF(*transferred > bytes,
292 "%s: HAL module read %zu bytes, which exceeds requested count %zu",
293 __func__, *transferred, bytes);
294 if (!mContext.getDataMQ()->read(static_cast<int8_t*>(buffer), *transferred)) {
295 ALOGE("%s: failed to read %zu bytes to data MQ", __func__, *transferred);
296 return NOT_ENOUGH_DATA;
297 }
298 }
299 mStreamPowerLog.log(buffer, *transferred);
300 return OK;
301}
302
303status_t StreamHalAidl::pause(StreamDescriptor::Reply* reply) {
304 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
305 TIME_CHECK();
306 if (!mStream) return NO_INIT;
307 return sendCommand(makeHalCommand<HalCommand::Tag::pause>(), reply,
308 true /*safeFromNonWorkerThread*/); // The workers stops its I/O activity first.
309}
310
311status_t StreamHalAidl::resume(StreamDescriptor::Reply* reply) {
312 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
313 TIME_CHECK();
314 if (!mStream) return NO_INIT;
315 if (mIsInput) {
316 return sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), reply);
317 } else {
318 return sendCommand(makeHalCommand<HalCommand::Tag::start>(), reply);
319 }
320}
321
322status_t StreamHalAidl::drain(bool earlyNotify, StreamDescriptor::Reply* reply) {
323 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
324 TIME_CHECK();
325 if (!mStream) return NO_INIT;
326 return sendCommand(makeHalCommand<HalCommand::Tag::drain>(
327 mIsInput ? StreamDescriptor::DrainMode::DRAIN_UNSPECIFIED :
328 earlyNotify ? StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY :
329 StreamDescriptor::DrainMode::DRAIN_ALL), reply);
330}
331
332status_t StreamHalAidl::flush(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::flush>(), reply,
337 true /*safeFromNonWorkerThread*/); // The workers stops its I/O activity first.
338}
339
340status_t StreamHalAidl::exit() {
341 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000342 TIME_CHECK();
343 if (!mStream) return NO_INIT;
344 ALOGE("%s not implemented yet", __func__);
345 return OK;
346}
347
348status_t StreamHalAidl::createMmapBuffer(int32_t minSizeFrames __unused,
349 struct audio_mmap_buffer_info *info __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800350 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000351 TIME_CHECK();
352 if (!mStream) return NO_INIT;
353 ALOGE("%s not implemented yet", __func__);
354 return OK;
355}
356
357status_t StreamHalAidl::getMmapPosition(struct audio_mmap_position *position __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800358 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000359 TIME_CHECK();
360 if (!mStream) return NO_INIT;
361 ALOGE("%s not implemented yet", __func__);
362 return OK;
363}
364
365status_t StreamHalAidl::setHalThreadPriority(int priority __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800366 // Obsolete, must be done by the HAL module.
Mikhail Naganov31d46652023-01-10 18:29:25 +0000367 return OK;
368}
369
370status_t StreamHalAidl::getHalPid(pid_t *pid __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800371 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000372 TIME_CHECK();
373 if (!mStream) return NO_INIT;
374 ALOGE("%s not implemented yet", __func__);
375 return OK;
376}
377
378bool StreamHalAidl::requestHalThreadPriority(pid_t threadPid __unused, pid_t threadId __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800379 // Obsolete, must be done by the HAL module.
380 return true;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000381}
382
383status_t StreamHalAidl::legacyCreateAudioPatch(const struct audio_port_config& port __unused,
384 std::optional<audio_source_t> source __unused,
385 audio_devices_t type __unused) {
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000386 // Obsolete since 'DeviceHalAidl.supportsAudioPatches' always returns 'true'.
387 return INVALID_OPERATION;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000388}
389
390status_t StreamHalAidl::legacyReleaseAudioPatch() {
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000391 // Obsolete since 'DeviceHalAidl.supportsAudioPatches' always returns 'true'.
392 return INVALID_OPERATION;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000393}
394
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800395status_t StreamHalAidl::sendCommand(
396 const ::aidl::android::hardware::audio::core::StreamDescriptor::Command &command,
397 ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply,
398 bool safeFromNonWorkerThread) {
399 // TIME_CHECK(); // TODO(b/238654698) reenable only when optimized.
400 if (!safeFromNonWorkerThread) {
401 const pid_t workerTid = mWorkerTid.load(std::memory_order_acquire);
402 LOG_ALWAYS_FATAL_IF(workerTid != gettid(),
403 "%s %s: must be invoked from the worker thread (%d)",
404 __func__, command.toString().c_str(), workerTid);
405 }
406 if (!mContext.getCommandMQ()->writeBlocking(&command, 1)) {
407 ALOGE("%s: failed to write command %s to MQ", __func__, command.toString().c_str());
408 return NOT_ENOUGH_DATA;
409 }
410 StreamDescriptor::Reply localReply{};
411 if (reply == nullptr) {
412 reply = &localReply;
413 }
414 if (!mContext.getReplyMQ()->readBlocking(reply, 1)) {
415 ALOGE("%s: failed to read from reply MQ, command %s", __func__, command.toString().c_str());
416 return NOT_ENOUGH_DATA;
417 }
418 {
419 std::lock_guard l(mLock);
420 mLastReply = *reply;
421 }
422 switch (reply->status) {
423 case STATUS_OK: return OK;
424 case STATUS_BAD_VALUE: return BAD_VALUE;
425 case STATUS_INVALID_OPERATION: return INVALID_OPERATION;
426 case STATUS_NOT_ENOUGH_DATA: return NOT_ENOUGH_DATA;
427 default:
428 ALOGE("%s: unexpected status %d returned for command %s",
429 __func__, reply->status, command.toString().c_str());
430 return INVALID_OPERATION;
431 }
432}
433
434status_t StreamHalAidl::updateCountersIfNeeded(
435 ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply) {
436 if (mWorkerTid.load(std::memory_order_acquire) == gettid()) {
437 if (const auto state = getState(); state != StreamDescriptor::State::ACTIVE &&
438 state != StreamDescriptor::State::DRAINING &&
439 state != StreamDescriptor::State::TRANSFERRING) {
440 return sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), reply);
441 }
442 }
443 if (reply != nullptr) {
444 std::lock_guard l(mLock);
445 *reply = mLastReply;
446 }
447 return OK;
448}
449
Mikhail Naganov31d46652023-01-10 18:29:25 +0000450StreamOutHalAidl::StreamOutHalAidl(
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800451 const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800452 const std::shared_ptr<IStreamOut>& stream, const sp<CallbackBroker>& callbackBroker)
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800453 : StreamHalAidl("StreamOutHalAidl", false /*isInput*/, config, nominalLatency,
454 std::move(context), getStreamCommon(stream)),
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800455 mStream(stream), mCallbackBroker(callbackBroker) {}
456
457StreamOutHalAidl::~StreamOutHalAidl() {
458 if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
459 broker->clearCallbacks(this);
460 }
461}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000462
463status_t StreamOutHalAidl::getLatency(uint32_t *latency) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800464 return StreamHalAidl::getLatency(latency);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000465}
466
467status_t StreamOutHalAidl::setVolume(float left __unused, float right __unused) {
468 TIME_CHECK();
469 if (!mStream) return NO_INIT;
470 ALOGE("%s not implemented yet", __func__);
471 return OK;
472}
473
474status_t StreamOutHalAidl::selectPresentation(int presentationId __unused, int programId __unused) {
475 TIME_CHECK();
476 if (!mStream) return NO_INIT;
477 ALOGE("%s not implemented yet", __func__);
478 return OK;
479}
480
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800481status_t StreamOutHalAidl::write(const void *buffer, size_t bytes, size_t *written) {
482 if (buffer == nullptr || written == nullptr) {
483 return BAD_VALUE;
484 }
485 // For the output scenario, 'transfer' does not modify the buffer.
486 return transfer(const_cast<void*>(buffer), bytes, written);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000487}
488
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800489status_t StreamOutHalAidl::getRenderPosition(uint32_t *dspFrames) {
490 if (dspFrames == nullptr) {
491 return BAD_VALUE;
492 }
493 int64_t aidlFrames = 0, aidlTimestamp = 0;
494 if (status_t status = getObservablePosition(&aidlFrames, &aidlTimestamp); status != OK) {
495 return OK;
496 }
497 *dspFrames = std::clamp<int64_t>(aidlFrames, 0, UINT32_MAX);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000498 return OK;
499}
500
501status_t StreamOutHalAidl::getNextWriteTimestamp(int64_t *timestamp __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800502 // Obsolete, use getPresentationPosition.
503 return INVALID_OPERATION;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000504}
505
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800506status_t StreamOutHalAidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000507 TIME_CHECK();
508 if (!mStream) return NO_INIT;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800509 if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
510 if (auto cb = callback.promote(); cb != nullptr) {
511 broker->setStreamOutCallback(this, cb);
512 } else {
513 // It is expected that the framework never passes a null pointer.
514 // In the AIDL model callbacks can't be "unregistered".
515 LOG_ALWAYS_FATAL("%s: received an expired or null callback pointer", __func__);
516 }
517 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000518 return OK;
519}
520
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800521status_t StreamOutHalAidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
522 if (supportsPause == nullptr || supportsResume == nullptr) {
523 return BAD_VALUE;
524 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000525 TIME_CHECK();
526 if (!mStream) return NO_INIT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800527 *supportsPause = *supportsResume = true;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000528 return OK;
529}
530
531status_t StreamOutHalAidl::pause() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800532 return StreamHalAidl::pause();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000533}
534
535status_t StreamOutHalAidl::resume() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800536 return StreamHalAidl::resume();
537}
538
539status_t StreamOutHalAidl::supportsDrain(bool *supportsDrain) {
540 if (supportsDrain == 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 *supportsDrain = true;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000546 return OK;
547}
548
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800549status_t StreamOutHalAidl::drain(bool earlyNotify) {
550 return StreamHalAidl::drain(earlyNotify);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000551}
552
553status_t StreamOutHalAidl::flush() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800554 return StreamHalAidl::flush();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000555}
556
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800557status_t StreamOutHalAidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
558 if (frames == nullptr || timestamp == nullptr) {
559 return BAD_VALUE;
560 }
561 int64_t aidlFrames = 0, aidlTimestamp = 0;
562 if (status_t status = getObservablePosition(&aidlFrames, &aidlTimestamp); status != OK) {
563 return status;
564 }
565 *frames = std::max<int64_t>(0, aidlFrames);
566 timestamp->tv_sec = aidlTimestamp / NANOS_PER_SECOND;
567 timestamp->tv_nsec = aidlTimestamp - timestamp->tv_sec * NANOS_PER_SECOND;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000568 return OK;
569}
570
571status_t StreamOutHalAidl::updateSourceMetadata(
572 const StreamOutHalInterface::SourceMetadata& sourceMetadata __unused) {
573 TIME_CHECK();
574 if (!mStream) return NO_INIT;
575 ALOGE("%s not implemented yet", __func__);
576 return OK;
577}
578
579status_t StreamOutHalAidl::getDualMonoMode(audio_dual_mono_mode_t* mode __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800580 TIME_CHECK();
581 if (!mStream) return NO_INIT;
582 ALOGE("%s not implemented yet", __func__);
583 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000584}
585
586status_t StreamOutHalAidl::setDualMonoMode(audio_dual_mono_mode_t mode __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800587 TIME_CHECK();
588 if (!mStream) return NO_INIT;
589 ALOGE("%s not implemented yet", __func__);
590 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000591}
592
593status_t StreamOutHalAidl::getAudioDescriptionMixLevel(float* leveldB __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800594 TIME_CHECK();
595 if (!mStream) return NO_INIT;
596 ALOGE("%s not implemented yet", __func__);
597 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000598}
599
600status_t StreamOutHalAidl::setAudioDescriptionMixLevel(float leveldB __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800601 TIME_CHECK();
602 if (!mStream) return NO_INIT;
603 ALOGE("%s not implemented yet", __func__);
604 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000605}
606
607status_t StreamOutHalAidl::getPlaybackRateParameters(
608 audio_playback_rate_t* playbackRate __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800609 TIME_CHECK();
610 if (!mStream) return NO_INIT;
611 ALOGE("%s not implemented yet", __func__);
612 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000613}
614
615status_t StreamOutHalAidl::setPlaybackRateParameters(
616 const audio_playback_rate_t& playbackRate __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800617 TIME_CHECK();
618 if (!mStream) return NO_INIT;
619 ALOGE("%s not implemented yet", __func__);
620 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000621}
622
623status_t StreamOutHalAidl::setEventCallback(
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800624 const sp<StreamOutHalInterfaceEventCallback>& callback) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800625 TIME_CHECK();
626 if (!mStream) return NO_INIT;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800627 if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
628 broker->setStreamOutEventCallback(this, callback);
629 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800630 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000631}
632
Mikhail Naganov31d46652023-01-10 18:29:25 +0000633status_t StreamOutHalAidl::setLatencyMode(audio_latency_mode_t mode __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800634 TIME_CHECK();
635 if (!mStream) return NO_INIT;
636 ALOGE("%s not implemented yet", __func__);
637 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000638};
639
640status_t StreamOutHalAidl::getRecommendedLatencyModes(
641 std::vector<audio_latency_mode_t> *modes __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800642 TIME_CHECK();
643 if (!mStream) return NO_INIT;
644 ALOGE("%s not implemented yet", __func__);
645 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000646};
647
648status_t StreamOutHalAidl::setLatencyModeCallback(
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800649 const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800650 TIME_CHECK();
651 if (!mStream) return NO_INIT;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800652 if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
653 broker->setStreamOutLatencyModeCallback(this, callback);
654 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800655 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000656};
657
Mikhail Naganov31d46652023-01-10 18:29:25 +0000658status_t StreamOutHalAidl::exit() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800659 return StreamHalAidl::exit();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000660}
661
662StreamInHalAidl::StreamInHalAidl(
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800663 const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
664 const std::shared_ptr<IStreamIn>& stream)
665 : StreamHalAidl("StreamInHalAidl", true /*isInput*/, config, nominalLatency,
666 std::move(context), getStreamCommon(stream)),
Mikhail Naganov31d46652023-01-10 18:29:25 +0000667 mStream(stream) {}
668
669status_t StreamInHalAidl::setGain(float gain __unused) {
670 TIME_CHECK();
671 if (!mStream) return NO_INIT;
672 ALOGE("%s not implemented yet", __func__);
673 return OK;
674}
675
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800676status_t StreamInHalAidl::read(void *buffer, size_t bytes, size_t *read) {
677 if (buffer == nullptr || read == nullptr) {
678 return BAD_VALUE;
679 }
680 return transfer(buffer, bytes, read);
681}
682
683status_t StreamInHalAidl::getInputFramesLost(uint32_t *framesLost) {
684 if (framesLost == nullptr) {
685 return BAD_VALUE;
686 }
687 int32_t aidlXruns = 0;
688 if (status_t status = getXruns(&aidlXruns); status != OK) {
689 return status;
690 }
691 *framesLost = std::max<int32_t>(0, aidlXruns);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000692 return OK;
693}
694
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800695status_t StreamInHalAidl::getCapturePosition(int64_t *frames, int64_t *time) {
696 if (frames == nullptr || time == nullptr) {
697 return BAD_VALUE;
698 }
699 return getObservablePosition(frames, time);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000700}
701
702status_t StreamInHalAidl::getActiveMicrophones(
703 std::vector<media::MicrophoneInfo> *microphones __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800704 TIME_CHECK();
705 if (!mStream) return NO_INIT;
706 ALOGE("%s not implemented yet", __func__);
707 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000708}
709
710status_t StreamInHalAidl::updateSinkMetadata(
711 const StreamInHalInterface::SinkMetadata& sinkMetadata __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800712 TIME_CHECK();
713 if (!mStream) return NO_INIT;
714 ALOGE("%s not implemented yet", __func__);
715 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000716}
717
718status_t StreamInHalAidl::setPreferredMicrophoneDirection(
719 audio_microphone_direction_t direction __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800720 TIME_CHECK();
721 if (!mStream) return NO_INIT;
722 ALOGE("%s not implemented yet", __func__);
723 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000724}
725
726status_t StreamInHalAidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800727 TIME_CHECK();
728 if (!mStream) return NO_INIT;
729 ALOGE("%s not implemented yet", __func__);
730 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000731}
732
733} // namespace android