blob: 04b70085017c8ee0b935ec1c050c0dbf991b7a51 [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 Lia0ad9f02023-03-02 21:46:19 +080024#include <media/AidlConversionCppNdk.h>
David Lia6fb5752023-02-23 15:32:47 +000025#include <media/AidlConversionUtil.h>
David Lia0ad9f02023-03-02 21:46:19 +080026#include <media/AudioParameter.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000027#include <mediautils/TimeCheck.h>
David Lia0ad9f02023-03-02 21:46:19 +080028#include <system/audio.h>
Mikhail Naganov31d46652023-01-10 18:29:25 +000029#include <utils/Log.h>
30
31#include "DeviceHalAidl.h"
32#include "StreamHalAidl.h"
33
David Lia6fb5752023-02-23 15:32:47 +000034using ::aidl::android::aidl_utils::statusTFromBinderStatus;
Mikhail Naganov31d46652023-01-10 18:29:25 +000035using ::aidl::android::hardware::audio::core::IStreamCommon;
36using ::aidl::android::hardware::audio::core::IStreamIn;
37using ::aidl::android::hardware::audio::core::IStreamOut;
38using ::aidl::android::hardware::audio::core::StreamDescriptor;
David Lia0ad9f02023-03-02 21:46:19 +080039using ::aidl::android::legacy2aidl_audio_channel_mask_t_AudioChannelLayout;
Mikhail Naganov31d46652023-01-10 18:29:25 +000040
41namespace android {
42
Mikhail Naganov89a9f742023-01-30 12:33:18 -080043using HalCommand = StreamDescriptor::Command;
44namespace {
45template<HalCommand::Tag cmd> HalCommand makeHalCommand() {
46 return HalCommand::make<cmd>(::aidl::android::media::audio::common::Void{});
47}
48template<HalCommand::Tag cmd, typename T> HalCommand makeHalCommand(T data) {
49 return HalCommand::make<cmd>(data);
50}
51} // namespace
52
Mikhail Naganovfab697c2023-01-11 19:33:13 +000053// static
54template<class T>
55std::shared_ptr<IStreamCommon> StreamHalAidl::getStreamCommon(const std::shared_ptr<T>& stream) {
56 std::shared_ptr<::aidl::android::hardware::audio::core::IStreamCommon> streamCommon;
57 if (stream != nullptr) {
58 if (ndk::ScopedAStatus status = stream->getStreamCommon(&streamCommon);
59 !status.isOk()) {
60 ALOGE("%s: failed to retrieve IStreamCommon instance: %s", __func__,
61 status.getDescription().c_str());
62 }
63 }
64 return streamCommon;
65}
66
Mikhail Naganov31d46652023-01-10 18:29:25 +000067StreamHalAidl::StreamHalAidl(
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080068 std::string_view className, bool isInput, const audio_config& config,
Mikhail Naganov89a9f742023-01-30 12:33:18 -080069 int32_t nominalLatency, StreamContextAidl&& context,
70 const std::shared_ptr<IStreamCommon>& stream)
Mikhail Naganov31d46652023-01-10 18:29:25 +000071 : ConversionHelperAidl(className),
72 mIsInput(isInput),
Mikhail Naganov5b1eed12023-01-25 11:29:11 -080073 mConfig(configToBase(config)),
Mikhail Naganov89a9f742023-01-30 12:33:18 -080074 mContext(std::move(context)),
Mikhail Naganov31d46652023-01-10 18:29:25 +000075 mStream(stream) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -080076 {
77 std::lock_guard l(mLock);
78 mLastReply.latencyMs = nominalLatency;
79 }
Mikhail Naganov31d46652023-01-10 18:29:25 +000080 // Instrument audio signal power logging.
81 // Note: This assumes channel mask, format, and sample rate do not change after creation.
82 if (audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
83 /* mStreamPowerLog.isUserDebugOrEngBuild() && */
84 StreamHalAidl::getAudioProperties(&config) == NO_ERROR) {
85 mStreamPowerLog.init(config.sample_rate, config.channel_mask, config.format);
86 }
87}
88
89StreamHalAidl::~StreamHalAidl() {
90 if (mStream != nullptr) {
91 ndk::ScopedAStatus status = mStream->close();
92 ALOGE_IF(!status.isOk(), "%s: status %s", __func__, status.getDescription().c_str());
93 }
94}
95
96status_t StreamHalAidl::getBufferSize(size_t *size) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -080097 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +000098 if (size == nullptr) {
99 return BAD_VALUE;
100 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800101 if (mContext.getFrameSizeBytes() == 0 || mContext.getBufferSizeFrames() == 0 ||
102 !mStream) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000103 return NO_INIT;
104 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800105 *size = mContext.getBufferSizeBytes();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000106 return OK;
107}
108
109status_t StreamHalAidl::getAudioProperties(audio_config_base_t *configBase) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800110 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000111 if (configBase == nullptr) {
112 return BAD_VALUE;
113 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800114 if (!mStream) return NO_INIT;
115 *configBase = mConfig;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000116 return OK;
117}
118
119status_t StreamHalAidl::setParameters(const String8& kvPairs __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800120 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000121 TIME_CHECK();
122 if (!mStream) return NO_INIT;
123 ALOGE("%s not implemented yet", __func__);
124 return OK;
125}
126
127status_t StreamHalAidl::getParameters(const String8& keys __unused, String8 *values) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800128 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000129 TIME_CHECK();
130 values->clear();
131 if (!mStream) return NO_INIT;
132 ALOGE("%s not implemented yet", __func__);
133 return OK;
134}
135
136status_t StreamHalAidl::getFrameSize(size_t *size) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800137 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000138 if (size == nullptr) {
139 return BAD_VALUE;
140 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800141 if (mContext.getFrameSizeBytes() == 0 || !mStream) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000142 return NO_INIT;
143 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800144 *size = mContext.getFrameSizeBytes();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000145 return OK;
146}
147
148status_t StreamHalAidl::addEffect(sp<EffectHalInterface> effect __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800149 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000150 TIME_CHECK();
151 if (!mStream) return NO_INIT;
152 ALOGE("%s not implemented yet", __func__);
153 return OK;
154}
155
156status_t StreamHalAidl::removeEffect(sp<EffectHalInterface> effect __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800157 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000158 TIME_CHECK();
159 if (!mStream) return NO_INIT;
160 ALOGE("%s not implemented yet", __func__);
161 return OK;
162}
163
164status_t StreamHalAidl::standby() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800165 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000166 TIME_CHECK();
167 if (!mStream) return NO_INIT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800168 const auto state = getState();
169 StreamDescriptor::Reply reply;
170 switch (state) {
171 case StreamDescriptor::State::ACTIVE:
172 if (status_t status = pause(&reply); status != OK) return status;
173 if (reply.state != StreamDescriptor::State::PAUSED) {
174 ALOGE("%s: unexpected stream state: %s (expected PAUSED)",
175 __func__, toString(reply.state).c_str());
176 return INVALID_OPERATION;
177 }
178 FALLTHROUGH_INTENDED;
179 case StreamDescriptor::State::PAUSED:
180 case StreamDescriptor::State::DRAIN_PAUSED:
Jasmine Cha105c66f2023-02-15 16:29:36 +0800181 if (mIsInput) return flush();
182 if (status_t status = flush(&reply); status != OK) return status;
183 if (reply.state != StreamDescriptor::State::IDLE) {
184 ALOGE("%s: unexpected stream state: %s (expected IDLE)",
185 __func__, toString(reply.state).c_str());
186 return INVALID_OPERATION;
187 }
188 FALLTHROUGH_INTENDED;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800189 case StreamDescriptor::State::IDLE:
190 if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::standby>(),
Jasmine Cha105c66f2023-02-15 16:29:36 +0800191 &reply, true /*safeFromNonWorkerThread*/); status != OK) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800192 return status;
193 }
194 if (reply.state != StreamDescriptor::State::STANDBY) {
195 ALOGE("%s: unexpected stream state: %s (expected STANDBY)",
196 __func__, toString(reply.state).c_str());
197 return INVALID_OPERATION;
198 }
199 FALLTHROUGH_INTENDED;
200 case StreamDescriptor::State::STANDBY:
201 return OK;
202 default:
203 ALOGE("%s: not supported from %s stream state %s",
204 __func__, mIsInput ? "input" : "output", toString(state).c_str());
205 return INVALID_OPERATION;
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800206 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000207}
208
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000209status_t StreamHalAidl::dump(int fd, const Vector<String16>& args) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800210 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000211 TIME_CHECK();
212 if (!mStream) return NO_INIT;
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000213 return mStream->dump(fd, Args(args).args(), args.size());
Mikhail Naganov31d46652023-01-10 18:29:25 +0000214}
215
216status_t StreamHalAidl::start() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800217 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000218 TIME_CHECK();
219 if (!mStream) return NO_INIT;
220 ALOGE("%s not implemented yet", __func__);
221 return OK;
222}
223
224status_t StreamHalAidl::stop() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800225 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
226 TIME_CHECK();
227 if (!mStream) return NO_INIT;
228 ALOGE("%s not implemented yet", __func__);
229 return OK;
230}
231
232status_t StreamHalAidl::getLatency(uint32_t *latency) {
233 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
234 if (!mStream) return NO_INIT;
235 StreamDescriptor::Reply reply;
236 if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
237 return status;
238 }
239 *latency = std::max<int32_t>(0, reply.latencyMs);
240 return OK;
241}
242
243status_t StreamHalAidl::getObservablePosition(int64_t *frames, int64_t *timestamp) {
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.observable.frames;
251 *timestamp = reply.observable.timeNs;
252 return OK;
253}
254
255status_t StreamHalAidl::getXruns(int32_t *frames) {
256 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
257 if (!mStream) return NO_INIT;
258 StreamDescriptor::Reply reply;
259 if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
260 return status;
261 }
262 *frames = reply.xrunFrames;
263 return OK;
264}
265
266status_t StreamHalAidl::transfer(void *buffer, size_t bytes, size_t *transferred) {
267 ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
Shunkai Yaoc6308712023-02-22 17:53:04 +0000268 // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800269 if (!mStream || mContext.getDataMQ() == nullptr) return NO_INIT;
270 mWorkerTid.store(gettid(), std::memory_order_release);
271 // Switch the stream into an active state if needed.
272 // Note: in future we may add support for priming the audio pipeline
273 // with data prior to enabling output (thus we can issue a "burst" command in the "standby"
274 // stream state), however this scenario wasn't supported by the HIDL HAL.
275 if (getState() == StreamDescriptor::State::STANDBY) {
276 StreamDescriptor::Reply reply;
277 if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply);
278 status != OK) {
279 return status;
280 }
281 if (reply.state != StreamDescriptor::State::IDLE) {
282 ALOGE("%s: failed to get the stream out of standby, actual state: %s",
283 __func__, toString(reply.state).c_str());
284 return INVALID_OPERATION;
285 }
286 }
287 if (!mIsInput) {
288 bytes = std::min(bytes, mContext.getDataMQ()->availableToWrite());
289 }
290 StreamDescriptor::Command burst =
291 StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(bytes);
292 if (!mIsInput) {
293 if (!mContext.getDataMQ()->write(static_cast<const int8_t*>(buffer), bytes)) {
294 ALOGE("%s: failed to write %zu bytes to data MQ", __func__, bytes);
295 return NOT_ENOUGH_DATA;
296 }
297 }
298 StreamDescriptor::Reply reply;
299 if (status_t status = sendCommand(burst, &reply); status != OK) {
300 return status;
301 }
Jasmine Chaad99fb02023-02-10 12:52:58 +0800302 *transferred = reply.fmqByteCount;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800303 if (mIsInput) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800304 LOG_ALWAYS_FATAL_IF(*transferred > bytes,
305 "%s: HAL module read %zu bytes, which exceeds requested count %zu",
306 __func__, *transferred, bytes);
Jasmine Cha105c66f2023-02-15 16:29:36 +0800307 if (auto toRead = mContext.getDataMQ()->availableToRead();
308 toRead != 0 && !mContext.getDataMQ()->read(static_cast<int8_t*>(buffer), toRead)) {
309 ALOGE("%s: failed to read %zu bytes to data MQ", __func__, toRead);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800310 return NOT_ENOUGH_DATA;
311 }
312 }
313 mStreamPowerLog.log(buffer, *transferred);
314 return OK;
315}
316
317status_t StreamHalAidl::pause(StreamDescriptor::Reply* reply) {
318 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
319 TIME_CHECK();
320 if (!mStream) return NO_INIT;
321 return sendCommand(makeHalCommand<HalCommand::Tag::pause>(), reply,
322 true /*safeFromNonWorkerThread*/); // The workers stops its I/O activity first.
323}
324
325status_t StreamHalAidl::resume(StreamDescriptor::Reply* reply) {
326 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
327 TIME_CHECK();
328 if (!mStream) return NO_INIT;
329 if (mIsInput) {
330 return sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), reply);
331 } else {
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800332 if (mContext.isAsynchronous()) {
333 // Handle pause-flush-resume sequence. 'flush' from PAUSED goes to
334 // IDLE. We move here from IDLE to ACTIVE (same as 'start' from PAUSED).
335 const auto state = getState();
336 if (state == StreamDescriptor::State::IDLE) {
337 StreamDescriptor::Reply localReply{};
338 StreamDescriptor::Reply* innerReply = reply ?: &localReply;
339 if (status_t status =
340 sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), innerReply);
341 status != OK) {
342 return status;
343 }
344 if (innerReply->state != StreamDescriptor::State::ACTIVE) {
345 ALOGE("%s: unexpected stream state: %s (expected ACTIVE)",
346 __func__, toString(innerReply->state).c_str());
347 return INVALID_OPERATION;
348 }
349 return OK;
350 }
351 }
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800352 return sendCommand(makeHalCommand<HalCommand::Tag::start>(), reply);
353 }
354}
355
356status_t StreamHalAidl::drain(bool earlyNotify, StreamDescriptor::Reply* reply) {
357 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
358 TIME_CHECK();
359 if (!mStream) return NO_INIT;
360 return sendCommand(makeHalCommand<HalCommand::Tag::drain>(
361 mIsInput ? StreamDescriptor::DrainMode::DRAIN_UNSPECIFIED :
362 earlyNotify ? StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY :
David Lia6fb5752023-02-23 15:32:47 +0000363 StreamDescriptor::DrainMode::DRAIN_ALL), reply,
364 true /*safeFromNonWorkerThread*/);
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800365}
366
367status_t StreamHalAidl::flush(StreamDescriptor::Reply* reply) {
368 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
369 TIME_CHECK();
370 if (!mStream) return NO_INIT;
371 return sendCommand(makeHalCommand<HalCommand::Tag::flush>(), reply,
372 true /*safeFromNonWorkerThread*/); // The workers stops its I/O activity first.
373}
374
375status_t StreamHalAidl::exit() {
376 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000377 TIME_CHECK();
378 if (!mStream) return NO_INIT;
379 ALOGE("%s not implemented yet", __func__);
380 return OK;
381}
382
383status_t StreamHalAidl::createMmapBuffer(int32_t minSizeFrames __unused,
384 struct audio_mmap_buffer_info *info __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800385 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000386 TIME_CHECK();
387 if (!mStream) return NO_INIT;
388 ALOGE("%s not implemented yet", __func__);
389 return OK;
390}
391
392status_t StreamHalAidl::getMmapPosition(struct audio_mmap_position *position __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800393 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000394 TIME_CHECK();
395 if (!mStream) return NO_INIT;
396 ALOGE("%s not implemented yet", __func__);
397 return OK;
398}
399
400status_t StreamHalAidl::setHalThreadPriority(int priority __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800401 // Obsolete, must be done by the HAL module.
Mikhail Naganov31d46652023-01-10 18:29:25 +0000402 return OK;
403}
404
405status_t StreamHalAidl::getHalPid(pid_t *pid __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800406 ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000407 TIME_CHECK();
408 if (!mStream) return NO_INIT;
409 ALOGE("%s not implemented yet", __func__);
410 return OK;
411}
412
413bool StreamHalAidl::requestHalThreadPriority(pid_t threadPid __unused, pid_t threadId __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800414 // Obsolete, must be done by the HAL module.
415 return true;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000416}
417
418status_t StreamHalAidl::legacyCreateAudioPatch(const struct audio_port_config& port __unused,
419 std::optional<audio_source_t> source __unused,
420 audio_devices_t type __unused) {
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000421 // Obsolete since 'DeviceHalAidl.supportsAudioPatches' always returns 'true'.
422 return INVALID_OPERATION;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000423}
424
425status_t StreamHalAidl::legacyReleaseAudioPatch() {
Mikhail Naganovfab697c2023-01-11 19:33:13 +0000426 // Obsolete since 'DeviceHalAidl.supportsAudioPatches' always returns 'true'.
427 return INVALID_OPERATION;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000428}
429
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800430status_t StreamHalAidl::sendCommand(
431 const ::aidl::android::hardware::audio::core::StreamDescriptor::Command &command,
432 ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply,
433 bool safeFromNonWorkerThread) {
Shunkai Yaoc6308712023-02-22 17:53:04 +0000434 // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800435 if (!safeFromNonWorkerThread) {
436 const pid_t workerTid = mWorkerTid.load(std::memory_order_acquire);
437 LOG_ALWAYS_FATAL_IF(workerTid != gettid(),
438 "%s %s: must be invoked from the worker thread (%d)",
439 __func__, command.toString().c_str(), workerTid);
440 }
441 if (!mContext.getCommandMQ()->writeBlocking(&command, 1)) {
442 ALOGE("%s: failed to write command %s to MQ", __func__, command.toString().c_str());
443 return NOT_ENOUGH_DATA;
444 }
445 StreamDescriptor::Reply localReply{};
446 if (reply == nullptr) {
447 reply = &localReply;
448 }
449 if (!mContext.getReplyMQ()->readBlocking(reply, 1)) {
450 ALOGE("%s: failed to read from reply MQ, command %s", __func__, command.toString().c_str());
451 return NOT_ENOUGH_DATA;
452 }
453 {
454 std::lock_guard l(mLock);
455 mLastReply = *reply;
456 }
457 switch (reply->status) {
458 case STATUS_OK: return OK;
459 case STATUS_BAD_VALUE: return BAD_VALUE;
460 case STATUS_INVALID_OPERATION: return INVALID_OPERATION;
461 case STATUS_NOT_ENOUGH_DATA: return NOT_ENOUGH_DATA;
462 default:
463 ALOGE("%s: unexpected status %d returned for command %s",
464 __func__, reply->status, command.toString().c_str());
465 return INVALID_OPERATION;
466 }
467}
468
469status_t StreamHalAidl::updateCountersIfNeeded(
470 ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply) {
471 if (mWorkerTid.load(std::memory_order_acquire) == gettid()) {
472 if (const auto state = getState(); state != StreamDescriptor::State::ACTIVE &&
473 state != StreamDescriptor::State::DRAINING &&
474 state != StreamDescriptor::State::TRANSFERRING) {
475 return sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), reply);
476 }
477 }
478 if (reply != nullptr) {
479 std::lock_guard l(mLock);
480 *reply = mLastReply;
481 }
482 return OK;
483}
484
Mikhail Naganov31d46652023-01-10 18:29:25 +0000485StreamOutHalAidl::StreamOutHalAidl(
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800486 const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800487 const std::shared_ptr<IStreamOut>& stream, const sp<CallbackBroker>& callbackBroker)
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800488 : StreamHalAidl("StreamOutHalAidl", false /*isInput*/, config, nominalLatency,
489 std::move(context), getStreamCommon(stream)),
David Lia0ad9f02023-03-02 21:46:19 +0800490 mStream(stream), mCallbackBroker(callbackBroker) {
491 // Initialize the offload metadata
492 mOffloadMetadata.sampleRate = static_cast<int32_t>(config.sample_rate);
493 mOffloadMetadata.channelMask = VALUE_OR_FATAL(
494 legacy2aidl_audio_channel_mask_t_AudioChannelLayout(config.channel_mask, false));
495 mOffloadMetadata.averageBitRatePerSecond = static_cast<int32_t>(config.offload_info.bit_rate);
496}
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800497
498StreamOutHalAidl::~StreamOutHalAidl() {
499 if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
500 broker->clearCallbacks(this);
501 }
502}
Mikhail Naganov31d46652023-01-10 18:29:25 +0000503
David Lia0ad9f02023-03-02 21:46:19 +0800504status_t StreamOutHalAidl::setParameters(const String8& kvPairs) {
505 if (!mStream) return NO_INIT;
506
507 AudioParameter parameters(kvPairs);
508 ALOGD("%s parameters: %s", __func__, parameters.toString().c_str());
509
510 if (filterAndUpdateOffloadMetadata(parameters) != OK) {
511 ALOGW("%s filtering or updating offload metadata gets failed", __func__);
512 }
513
514 return StreamHalAidl::setParameters(parameters.toString());
515}
516
Mikhail Naganov31d46652023-01-10 18:29:25 +0000517status_t StreamOutHalAidl::getLatency(uint32_t *latency) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800518 return StreamHalAidl::getLatency(latency);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000519}
520
David Lia6fb5752023-02-23 15:32:47 +0000521status_t StreamOutHalAidl::setVolume(float left, float right) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000522 TIME_CHECK();
523 if (!mStream) return NO_INIT;
David Lia6fb5752023-02-23 15:32:47 +0000524 return statusTFromBinderStatus(mStream->setHwVolume({left, right}));
Mikhail Naganov31d46652023-01-10 18:29:25 +0000525}
526
527status_t StreamOutHalAidl::selectPresentation(int presentationId __unused, int programId __unused) {
528 TIME_CHECK();
529 if (!mStream) return NO_INIT;
530 ALOGE("%s not implemented yet", __func__);
531 return OK;
532}
533
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800534status_t StreamOutHalAidl::write(const void *buffer, size_t bytes, size_t *written) {
535 if (buffer == nullptr || written == nullptr) {
536 return BAD_VALUE;
537 }
538 // For the output scenario, 'transfer' does not modify the buffer.
539 return transfer(const_cast<void*>(buffer), bytes, written);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000540}
541
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800542status_t StreamOutHalAidl::getRenderPosition(uint32_t *dspFrames) {
543 if (dspFrames == nullptr) {
544 return BAD_VALUE;
545 }
546 int64_t aidlFrames = 0, aidlTimestamp = 0;
547 if (status_t status = getObservablePosition(&aidlFrames, &aidlTimestamp); status != OK) {
548 return OK;
549 }
550 *dspFrames = std::clamp<int64_t>(aidlFrames, 0, UINT32_MAX);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000551 return OK;
552}
553
554status_t StreamOutHalAidl::getNextWriteTimestamp(int64_t *timestamp __unused) {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800555 // Obsolete, use getPresentationPosition.
556 return INVALID_OPERATION;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000557}
558
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800559status_t StreamOutHalAidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
Mikhail Naganov31d46652023-01-10 18:29:25 +0000560 TIME_CHECK();
561 if (!mStream) return NO_INIT;
Mikhail Naganov712d71b2023-02-23 17:57:16 -0800562 if (!mContext.isAsynchronous()) {
563 ALOGE("%s: the callback is intended for asynchronous streams only", __func__);
564 return INVALID_OPERATION;
565 }
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800566 if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
567 if (auto cb = callback.promote(); cb != nullptr) {
568 broker->setStreamOutCallback(this, cb);
569 } else {
570 // It is expected that the framework never passes a null pointer.
571 // In the AIDL model callbacks can't be "unregistered".
572 LOG_ALWAYS_FATAL("%s: received an expired or null callback pointer", __func__);
573 }
574 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000575 return OK;
576}
577
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800578status_t StreamOutHalAidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
579 if (supportsPause == nullptr || supportsResume == nullptr) {
580 return BAD_VALUE;
581 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000582 TIME_CHECK();
583 if (!mStream) return NO_INIT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800584 *supportsPause = *supportsResume = true;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000585 return OK;
586}
587
588status_t StreamOutHalAidl::pause() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800589 return StreamHalAidl::pause();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000590}
591
592status_t StreamOutHalAidl::resume() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800593 return StreamHalAidl::resume();
594}
595
596status_t StreamOutHalAidl::supportsDrain(bool *supportsDrain) {
597 if (supportsDrain == nullptr) {
598 return BAD_VALUE;
599 }
Mikhail Naganov31d46652023-01-10 18:29:25 +0000600 TIME_CHECK();
601 if (!mStream) return NO_INIT;
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800602 *supportsDrain = true;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000603 return OK;
604}
605
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800606status_t StreamOutHalAidl::drain(bool earlyNotify) {
607 return StreamHalAidl::drain(earlyNotify);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000608}
609
610status_t StreamOutHalAidl::flush() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800611 return StreamHalAidl::flush();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000612}
613
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800614status_t StreamOutHalAidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
615 if (frames == nullptr || timestamp == nullptr) {
616 return BAD_VALUE;
617 }
618 int64_t aidlFrames = 0, aidlTimestamp = 0;
619 if (status_t status = getObservablePosition(&aidlFrames, &aidlTimestamp); status != OK) {
620 return status;
621 }
622 *frames = std::max<int64_t>(0, aidlFrames);
623 timestamp->tv_sec = aidlTimestamp / NANOS_PER_SECOND;
624 timestamp->tv_nsec = aidlTimestamp - timestamp->tv_sec * NANOS_PER_SECOND;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000625 return OK;
626}
627
628status_t StreamOutHalAidl::updateSourceMetadata(
629 const StreamOutHalInterface::SourceMetadata& sourceMetadata __unused) {
630 TIME_CHECK();
631 if (!mStream) return NO_INIT;
632 ALOGE("%s not implemented yet", __func__);
633 return OK;
634}
635
636status_t StreamOutHalAidl::getDualMonoMode(audio_dual_mono_mode_t* mode __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800637 TIME_CHECK();
638 if (!mStream) return NO_INIT;
639 ALOGE("%s not implemented yet", __func__);
640 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000641}
642
643status_t StreamOutHalAidl::setDualMonoMode(audio_dual_mono_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::getAudioDescriptionMixLevel(float* leveldB __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800651 TIME_CHECK();
652 if (!mStream) return NO_INIT;
653 ALOGE("%s not implemented yet", __func__);
654 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000655}
656
657status_t StreamOutHalAidl::setAudioDescriptionMixLevel(float leveldB __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800658 TIME_CHECK();
659 if (!mStream) return NO_INIT;
660 ALOGE("%s not implemented yet", __func__);
661 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000662}
663
664status_t StreamOutHalAidl::getPlaybackRateParameters(
665 audio_playback_rate_t* playbackRate __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800666 TIME_CHECK();
667 if (!mStream) return NO_INIT;
668 ALOGE("%s not implemented yet", __func__);
David Lia6fb5752023-02-23 15:32:47 +0000669 return BAD_VALUE;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000670}
671
672status_t StreamOutHalAidl::setPlaybackRateParameters(
673 const audio_playback_rate_t& playbackRate __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800674 TIME_CHECK();
675 if (!mStream) return NO_INIT;
676 ALOGE("%s not implemented yet", __func__);
David Lia6fb5752023-02-23 15:32:47 +0000677 return BAD_VALUE;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000678}
679
680status_t StreamOutHalAidl::setEventCallback(
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800681 const sp<StreamOutHalInterfaceEventCallback>& callback) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800682 TIME_CHECK();
683 if (!mStream) return NO_INIT;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800684 if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
685 broker->setStreamOutEventCallback(this, callback);
686 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800687 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000688}
689
Mikhail Naganov31d46652023-01-10 18:29:25 +0000690status_t StreamOutHalAidl::setLatencyMode(audio_latency_mode_t mode __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800691 TIME_CHECK();
692 if (!mStream) return NO_INIT;
693 ALOGE("%s not implemented yet", __func__);
694 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000695};
696
697status_t StreamOutHalAidl::getRecommendedLatencyModes(
698 std::vector<audio_latency_mode_t> *modes __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800699 TIME_CHECK();
700 if (!mStream) return NO_INIT;
701 ALOGE("%s not implemented yet", __func__);
702 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000703};
704
705status_t StreamOutHalAidl::setLatencyModeCallback(
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800706 const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800707 TIME_CHECK();
708 if (!mStream) return NO_INIT;
Mikhail Naganovdfd594e2023-02-08 16:59:41 -0800709 if (auto broker = mCallbackBroker.promote(); broker != nullptr) {
710 broker->setStreamOutLatencyModeCallback(this, callback);
711 }
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800712 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000713};
714
Mikhail Naganov31d46652023-01-10 18:29:25 +0000715status_t StreamOutHalAidl::exit() {
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800716 return StreamHalAidl::exit();
Mikhail Naganov31d46652023-01-10 18:29:25 +0000717}
718
David Lia0ad9f02023-03-02 21:46:19 +0800719status_t StreamOutHalAidl::filterAndUpdateOffloadMetadata(AudioParameter &parameters) {
720 TIME_CHECK();
721
722 if (parameters.containsKey(String8(AudioParameter::keyOffloadCodecAverageBitRate)) ||
723 parameters.containsKey(String8(AudioParameter::keyOffloadCodecSampleRate)) ||
724 parameters.containsKey(String8(AudioParameter::keyOffloadCodecChannels)) ||
725 parameters.containsKey(String8(AudioParameter::keyOffloadCodecDelaySamples)) ||
726 parameters.containsKey(String8(AudioParameter::keyOffloadCodecPaddingSamples))) {
727 int value = 0;
728 if (parameters.getInt(String8(AudioParameter::keyOffloadCodecAverageBitRate), value)
729 == NO_ERROR) {
730 if (value <= 0) {
731 return BAD_VALUE;
732 }
733 mOffloadMetadata.averageBitRatePerSecond = value;
734 parameters.remove(String8(AudioParameter::keyOffloadCodecAverageBitRate));
735 }
736
737 if (parameters.getInt(String8(AudioParameter::keyOffloadCodecSampleRate), value)
738 == NO_ERROR) {
739 if (value <= 0) {
740 return BAD_VALUE;
741 }
742 mOffloadMetadata.sampleRate = value;
743 parameters.remove(String8(AudioParameter::keyOffloadCodecSampleRate));
744 }
745
746 if (parameters.getInt(String8(AudioParameter::keyOffloadCodecChannels), value)
747 == NO_ERROR) {
748 if (value <= 0) {
749 return BAD_VALUE;
750 }
751 audio_channel_mask_t channel_mask =
752 audio_channel_out_mask_from_count(static_cast<uint32_t>(value));
753 if (channel_mask == AUDIO_CHANNEL_INVALID) {
754 return BAD_VALUE;
755 }
756 mOffloadMetadata.channelMask =
757 VALUE_OR_RETURN_STATUS(legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
758 channel_mask, false));
759 parameters.remove(String8(AudioParameter::keyOffloadCodecChannels));
760 }
761
762 // The legacy keys are misnamed. The delay and padding are in frame.
763 if (parameters.getInt(String8(AudioParameter::keyOffloadCodecDelaySamples), value)
764 == NO_ERROR) {
765 if (value < 0) {
766 return BAD_VALUE;
767 }
768 mOffloadMetadata.delayFrames = value;
769 parameters.remove(String8(AudioParameter::keyOffloadCodecDelaySamples));
770 }
771
772 if (parameters.getInt(String8(AudioParameter::keyOffloadCodecPaddingSamples), value)
773 == NO_ERROR) {
774 if (value < 0) {
775 return BAD_VALUE;
776 }
777 mOffloadMetadata.paddingFrames = value;
778 parameters.remove(String8(AudioParameter::keyOffloadCodecPaddingSamples));
779 }
780
781 ALOGD("%s set offload metadata %s", __func__, mOffloadMetadata.toString().c_str());
782 status_t status = statusTFromBinderStatus(mStream->updateOffloadMetadata(mOffloadMetadata));
783 if (status != OK) {
784 ALOGE("%s: updateOffloadMetadata failed %d", __func__, status);
785 return status;
786 }
787 }
788 return OK;
789}
790
Mikhail Naganov31d46652023-01-10 18:29:25 +0000791StreamInHalAidl::StreamInHalAidl(
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800792 const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
793 const std::shared_ptr<IStreamIn>& stream)
794 : StreamHalAidl("StreamInHalAidl", true /*isInput*/, config, nominalLatency,
795 std::move(context), getStreamCommon(stream)),
Mikhail Naganov31d46652023-01-10 18:29:25 +0000796 mStream(stream) {}
797
798status_t StreamInHalAidl::setGain(float gain __unused) {
799 TIME_CHECK();
800 if (!mStream) return NO_INIT;
801 ALOGE("%s not implemented yet", __func__);
802 return OK;
803}
804
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800805status_t StreamInHalAidl::read(void *buffer, size_t bytes, size_t *read) {
806 if (buffer == nullptr || read == nullptr) {
807 return BAD_VALUE;
808 }
809 return transfer(buffer, bytes, read);
810}
811
812status_t StreamInHalAidl::getInputFramesLost(uint32_t *framesLost) {
813 if (framesLost == nullptr) {
814 return BAD_VALUE;
815 }
816 int32_t aidlXruns = 0;
817 if (status_t status = getXruns(&aidlXruns); status != OK) {
818 return status;
819 }
820 *framesLost = std::max<int32_t>(0, aidlXruns);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000821 return OK;
822}
823
Mikhail Naganov89a9f742023-01-30 12:33:18 -0800824status_t StreamInHalAidl::getCapturePosition(int64_t *frames, int64_t *time) {
825 if (frames == nullptr || time == nullptr) {
826 return BAD_VALUE;
827 }
828 return getObservablePosition(frames, time);
Mikhail Naganov31d46652023-01-10 18:29:25 +0000829}
830
831status_t StreamInHalAidl::getActiveMicrophones(
Mikhail Naganov2a6a3012023-02-13 11:45:03 -0800832 std::vector<media::MicrophoneInfoFw> *microphones __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800833 TIME_CHECK();
834 if (!mStream) return NO_INIT;
835 ALOGE("%s not implemented yet", __func__);
836 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000837}
838
839status_t StreamInHalAidl::updateSinkMetadata(
840 const StreamInHalInterface::SinkMetadata& sinkMetadata __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800841 TIME_CHECK();
842 if (!mStream) return NO_INIT;
843 ALOGE("%s not implemented yet", __func__);
844 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000845}
846
847status_t StreamInHalAidl::setPreferredMicrophoneDirection(
848 audio_microphone_direction_t direction __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800849 TIME_CHECK();
850 if (!mStream) return NO_INIT;
851 ALOGE("%s not implemented yet", __func__);
852 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000853}
854
855status_t StreamInHalAidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
Mikhail Naganov5b1eed12023-01-25 11:29:11 -0800856 TIME_CHECK();
857 if (!mStream) return NO_INIT;
858 ALOGE("%s not implemented yet", __func__);
859 return OK;
Mikhail Naganov31d46652023-01-10 18:29:25 +0000860}
861
862} // namespace android