blob: 82062cc98369a447d1e054dbd7746c2b5c2b517c [file] [log] [blame]
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001/*
2 * Copyright (C) 2016 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 "StreamHalHidl"
18//#define LOG_NDEBUG 0
19
Mikhail Naganov247b5f92021-01-15 19:16:12 +000020#include <android/hidl/manager/1.0/IServiceManager.h>
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080021#include <hwbinder/IPCThreadState.h>
Mikhail Naganovac917ac2018-11-28 14:03:52 -080022#include <media/AudioParameter.h>
Ytai Ben-Tsvidb6f8982022-02-07 12:06:23 -080023#include <mediautils/memory.h>
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080024#include <mediautils/SchedulingPolicyService.h>
Andy Hung224f82f2022-03-22 00:00:49 -070025#include <mediautils/TimeCheck.h>
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080026#include <utils/Log.h>
Mikhail Naganov2a6a3012023-02-13 11:45:03 -080027#if MAJOR_VERSION >= 4
28#include <media/AidlConversion.h>
29#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080030
Mikhail Naganov6718c392022-01-27 22:17:21 +000031#include PATH(android/hardware/audio/CORE_TYPES_FILE_VERSION/IStreamOutCallback.h)
Mikhail Naganov247b5f92021-01-15 19:16:12 +000032#include <HidlUtils.h>
33#include <util/CoreUtils.h>
34
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080035#include "DeviceHalHidl.h"
Mikhail Naganov247b5f92021-01-15 19:16:12 +000036#include "ParameterUtils.h"
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080037#include "StreamHalHidl.h"
38
Mikhail Naganov6718c392022-01-27 22:17:21 +000039using ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::implementation::HidlUtils;
40using ::android::hardware::audio::CORE_TYPES_CPP_VERSION::implementation::CoreUtils;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080041using ::android::hardware::MQDescriptorSync;
42using ::android::hardware::Return;
43using ::android::hardware::Void;
Kevin Rocarddf9b4202018-05-10 19:56:08 -070044
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080045namespace android {
46
Mikhail Naganovaccbe8a2022-02-03 23:45:36 +000047using ReadCommand = ::android::hardware::audio::CORE_TYPES_CPP_VERSION::IStreamIn::ReadCommand;
Mikhail Naganov9ccaa162018-12-12 10:27:29 -080048
Mikhail Naganov6718c392022-01-27 22:17:21 +000049using namespace ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION;
50using namespace ::android::hardware::audio::CORE_TYPES_CPP_VERSION;
Mikhail Naganov9ccaa162018-12-12 10:27:29 -080051
Andy Hung224f82f2022-03-22 00:00:49 -070052StreamHalHidl::StreamHalHidl(std::string_view className, IStream *stream)
Mikhail Naganov288a3432022-03-25 00:29:56 +000053 : CoreConversionHelperHidl(className),
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080054 mStream(stream),
55 mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT),
56 mCachedBufferSize(0){
57
58 // Instrument audio signal power logging.
59 // Note: This assumes channel mask, format, and sample rate do not change after creation.
Mikhail Naganov247b5f92021-01-15 19:16:12 +000060 audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
61 if (/* mStreamPowerLog.isUserDebugOrEngBuild() && */
Mikhail Naganov560637e2021-03-31 22:40:13 +000062 StreamHalHidl::getAudioProperties(&config) == NO_ERROR) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +000063 mStreamPowerLog.init(config.sample_rate, config.channel_mask, config.format);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080064 }
65}
66
Andy Hungacb5b982021-01-20 10:12:00 -080067StreamHalHidl::~StreamHalHidl() {
68 // The last step is to flush all binder commands so that the deletion
69 // of IStreamIn / IStreamOut (mStream) is issued with less delay. See b/35394629.
70 hardware::IPCThreadState::self()->flushCommands();
71}
72
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080073status_t StreamHalHidl::getBufferSize(size_t *size) {
Andy Hung224f82f2022-03-22 00:00:49 -070074 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080075 if (!mStream) return NO_INIT;
76 status_t status = processReturn("getBufferSize", mStream->getBufferSize(), size);
77 if (status == OK) {
78 mCachedBufferSize = *size;
79 }
80 return status;
81}
82
Mikhail Naganov560637e2021-03-31 22:40:13 +000083status_t StreamHalHidl::getAudioProperties(audio_config_base_t *configBase) {
Andy Hung224f82f2022-03-22 00:00:49 -070084 TIME_CHECK();
Mikhail Naganov560637e2021-03-31 22:40:13 +000085 *configBase = AUDIO_CONFIG_BASE_INITIALIZER;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080086 if (!mStream) return NO_INIT;
Mikhail Naganov247b5f92021-01-15 19:16:12 +000087#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080088 Return<void> ret = mStream->getAudioProperties(
Kevin Rocardb9cfbf12018-02-23 19:11:06 -080089 [&](uint32_t sr, auto m, auto f) {
Mikhail Naganov560637e2021-03-31 22:40:13 +000090 configBase->sample_rate = sr;
91 configBase->channel_mask = static_cast<audio_channel_mask_t>(m);
92 configBase->format = static_cast<audio_format_t>(f);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080093 });
94 return processReturn("getAudioProperties", ret);
Mikhail Naganov247b5f92021-01-15 19:16:12 +000095#else
96 Result retval;
97 status_t conversionStatus = BAD_VALUE;
Mikhail Naganov247b5f92021-01-15 19:16:12 +000098 Return<void> ret = mStream->getAudioProperties(
99 [&](Result r, const AudioConfigBase& config) {
100 retval = r;
101 if (retval == Result::OK) {
Mikhail Naganov560637e2021-03-31 22:40:13 +0000102 conversionStatus = HidlUtils::audioConfigBaseToHal(config, configBase);
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000103 }
104 });
105 if (status_t status = processReturn("getAudioProperties", ret, retval); status == NO_ERROR) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000106 return conversionStatus;
107 } else {
108 return status;
109 }
110#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800111}
112
113status_t StreamHalHidl::setParameters(const String8& kvPairs) {
Andy Hung224f82f2022-03-22 00:00:49 -0700114 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800115 if (!mStream) return NO_INIT;
116 hidl_vec<ParameterValue> hidlParams;
117 status_t status = parametersFromHal(kvPairs, &hidlParams);
118 if (status != OK) return status;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800119 return processReturn("setParameters",
Dean Wheatley7b417a22019-01-31 20:39:42 +1100120 utils::setParameters(mStream, {} /* context */, hidlParams));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800121}
122
123status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
Andy Hung224f82f2022-03-22 00:00:49 -0700124 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800125 values->clear();
126 if (!mStream) return NO_INIT;
127 hidl_vec<hidl_string> hidlKeys;
128 status_t status = keysFromHal(keys, &hidlKeys);
129 if (status != OK) return status;
130 Result retval;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800131 Return<void> ret = utils::getParameters(
132 mStream,
133 {} /* context */,
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800134 hidlKeys,
135 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
136 retval = r;
137 if (retval == Result::OK) {
138 parametersToHal(parameters, values);
139 }
140 });
141 return processReturn("getParameters", ret, retval);
142}
143
144status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
Andy Hung224f82f2022-03-22 00:00:49 -0700145 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800146 if (!mStream) return NO_INIT;
Mikhail Naganov6718c392022-01-27 22:17:21 +0000147 return processReturn("addEffect", mStream->addEffect(effect->effectId()));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800148}
149
150status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
Andy Hung224f82f2022-03-22 00:00:49 -0700151 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800152 if (!mStream) return NO_INIT;
Mikhail Naganov6718c392022-01-27 22:17:21 +0000153 return processReturn("removeEffect", mStream->removeEffect(effect->effectId()));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800154}
155
156status_t StreamHalHidl::standby() {
Andy Hung224f82f2022-03-22 00:00:49 -0700157 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800158 if (!mStream) return NO_INIT;
159 return processReturn("standby", mStream->standby());
160}
161
Andy Hung61589a42021-06-16 09:37:53 -0700162status_t StreamHalHidl::dump(int fd, const Vector<String16>& args) {
Andy Hung224f82f2022-03-22 00:00:49 -0700163 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800164 if (!mStream) return NO_INIT;
165 native_handle_t* hidlHandle = native_handle_create(1, 0);
166 hidlHandle->data[0] = fd;
Andy Hung61589a42021-06-16 09:37:53 -0700167 hidl_vec<hidl_string> hidlArgs;
168 argsFromHal(args, &hidlArgs);
169 Return<void> ret = mStream->debug(hidlHandle, hidlArgs);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800170 native_handle_delete(hidlHandle);
Andy Hunge72ff022021-08-16 10:16:15 -0700171
172 // TODO(b/111997867, b/177271958) Workaround - remove when fixed.
173 // A Binder transmitted fd may not close immediately due to a race condition b/111997867
174 // when the remote binder thread removes the last refcount to the fd blocks in the
175 // kernel for binder activity. We send a Binder ping() command to unblock the thread
176 // and complete the fd close / release.
177 //
178 // See DeviceHalHidl::dump(), EffectHalHidl::dump(), StreamHalHidl::dump(),
179 // EffectsFactoryHalHidl::dumpEffects().
180
181 (void)mStream->ping(); // synchronous Binder call
182
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800183 mStreamPowerLog.dump(fd);
184 return processReturn("dump", ret);
185}
186
187status_t StreamHalHidl::start() {
Andy Hung224f82f2022-03-22 00:00:49 -0700188 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800189 if (!mStream) return NO_INIT;
190 return processReturn("start", mStream->start());
191}
192
193status_t StreamHalHidl::stop() {
Andy Hung224f82f2022-03-22 00:00:49 -0700194 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800195 if (!mStream) return NO_INIT;
196 return processReturn("stop", mStream->stop());
197}
198
199status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
200 struct audio_mmap_buffer_info *info) {
Andy Hung224f82f2022-03-22 00:00:49 -0700201 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800202 Result retval;
203 Return<void> ret = mStream->createMmapBuffer(
204 minSizeFrames,
205 [&](Result r, const MmapBufferInfo& hidlInfo) {
206 retval = r;
207 if (retval == Result::OK) {
208 const native_handle *handle = hidlInfo.sharedMemory.handle();
209 if (handle->numFds > 0) {
210 info->shared_memory_fd = handle->data[0];
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800211#if MAJOR_VERSION >= 4
Kevin Rocard734334f2018-07-12 19:37:41 -0700212 info->flags = audio_mmap_buffer_flag(hidlInfo.flags);
213#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800214 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
Kevin Rocard734334f2018-07-12 19:37:41 -0700215 // Negative buffer size frame was a hack in O and P to
216 // indicate that the buffer is shareable to applications
217 if (info->buffer_size_frames < 0) {
218 info->buffer_size_frames *= -1;
219 info->flags = audio_mmap_buffer_flag(
220 info->flags | AUDIO_MMAP_APPLICATION_SHAREABLE);
221 }
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800222 info->burst_size_frames = hidlInfo.burstSizeFrames;
223 // info->shared_memory_address is not needed in HIDL context
224 info->shared_memory_address = NULL;
225 } else {
226 retval = Result::NOT_INITIALIZED;
227 }
228 }
229 });
230 return processReturn("createMmapBuffer", ret, retval);
231}
232
233status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
Andy Hung224f82f2022-03-22 00:00:49 -0700234 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800235 Result retval;
236 Return<void> ret = mStream->getMmapPosition(
237 [&](Result r, const MmapPosition& hidlPosition) {
238 retval = r;
239 if (retval == Result::OK) {
240 position->time_nanoseconds = hidlPosition.timeNanoseconds;
241 position->position_frames = hidlPosition.positionFrames;
242 }
243 });
244 return processReturn("getMmapPosition", ret, retval);
245}
246
247status_t StreamHalHidl::setHalThreadPriority(int priority) {
248 mHalThreadPriority = priority;
249 return OK;
250}
251
252status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
253 if (mCachedBufferSize != 0) {
254 *size = mCachedBufferSize;
255 return OK;
256 }
257 return getBufferSize(size);
258}
259
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000260status_t StreamHalHidl::getHalPid(pid_t *pid) {
261 using ::android::hidl::base::V1_0::DebugInfo;
262 using ::android::hidl::manager::V1_0::IServiceManager;
Andy Hung224f82f2022-03-22 00:00:49 -0700263 TIME_CHECK();
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000264 DebugInfo debugInfo;
265 auto ret = mStream->getDebugInfo([&] (const auto &info) {
266 debugInfo = info;
267 });
268 if (!ret.isOk()) {
269 return INVALID_OPERATION;
270 }
271 if (debugInfo.pid != (int)IServiceManager::PidConstant::NO_PID) {
272 *pid = debugInfo.pid;
273 return NO_ERROR;
274 }
275 return NAME_NOT_FOUND;
276}
277
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800278bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
279 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
280 return true;
281 }
282 int err = requestPriority(
283 threadPid, threadId,
284 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
285 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
286 mHalThreadPriority, threadPid, threadId, err);
287 // Audio will still work, but latency will be higher and sometimes unacceptable.
288 return err == 0;
289}
290
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800291status_t StreamHalHidl::legacyCreateAudioPatch(const struct audio_port_config& port,
292 std::optional<audio_source_t> source,
293 audio_devices_t type) {
Andy Hung224f82f2022-03-22 00:00:49 -0700294 TIME_CHECK();
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800295 LOG_ALWAYS_FATAL_IF(port.type != AUDIO_PORT_TYPE_DEVICE, "port type must be device");
Ytai Ben-Tsvidb6f8982022-02-07 12:06:23 -0800296 unique_malloced_ptr<char> address;
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800297 if (strcmp(port.ext.device.address, "") != 0) {
298 // FIXME: we only support address on first sink with HAL version < 3.0
Ytai Ben-Tsvidb6f8982022-02-07 12:06:23 -0800299 address.reset(
300 audio_device_address_to_parameter(port.ext.device.type, port.ext.device.address));
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800301 } else {
Ytai Ben-Tsvidb6f8982022-02-07 12:06:23 -0800302 address.reset((char*)calloc(1, 1));
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800303 }
Ytai Ben-Tsvidb6f8982022-02-07 12:06:23 -0800304 AudioParameter param = AudioParameter(String8(address.get()));
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800305 param.addInt(String8(AudioParameter::keyRouting), (int)type);
306 if (source.has_value()) {
307 param.addInt(String8(AudioParameter::keyInputSource), (int)source.value());
308 }
309 return setParameters(param.toString());
310}
311
312status_t StreamHalHidl::legacyReleaseAudioPatch() {
Andy Hung224f82f2022-03-22 00:00:49 -0700313 TIME_CHECK();
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800314 AudioParameter param;
315 param.addInt(String8(AudioParameter::keyRouting), 0);
316 return setParameters(param.toString());
317}
318
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800319namespace {
320
321/* Notes on callback ownership.
322
323This is how (Hw)Binder ownership model looks like. The server implementation
324is owned by Binder framework (via sp<>). Proxies are owned by clients.
325When the last proxy disappears, Binder framework releases the server impl.
326
327Thus, it is not needed to keep any references to StreamOutCallback (this is
328the server impl) -- it will live as long as HAL server holds a strong ref to
329IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
330from the destructor of StreamOutHalHidl.
331
332The callback only keeps a weak reference to the stream. The stream is owned
333by AudioFlinger.
334
335*/
336
337struct StreamOutCallback : public IStreamOutCallback {
338 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
339
340 // IStreamOutCallback implementation
341 Return<void> onWriteReady() override {
342 sp<StreamOutHalHidl> stream = mStream.promote();
343 if (stream != 0) {
344 stream->onWriteReady();
345 }
346 return Void();
347 }
348
349 Return<void> onDrainReady() override {
350 sp<StreamOutHalHidl> stream = mStream.promote();
351 if (stream != 0) {
352 stream->onDrainReady();
353 }
354 return Void();
355 }
356
357 Return<void> onError() override {
358 sp<StreamOutHalHidl> stream = mStream.promote();
359 if (stream != 0) {
360 stream->onError();
361 }
362 return Void();
363 }
364
365 private:
Andy Hung638f45b2021-01-18 20:02:56 -0800366 const wp<StreamOutHalHidl> mStream;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800367};
368
369} // namespace
370
Mikhail Naganov6718c392022-01-27 22:17:21 +0000371StreamOutHalHidl::StreamOutHalHidl(
372 const sp<::android::hardware::audio::CPP_VERSION::IStreamOut>& stream)
Andy Hung224f82f2022-03-22 00:00:49 -0700373 : StreamHalHidl("StreamOutHalHidl", stream.get())
374 , mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800375}
376
377StreamOutHalHidl::~StreamOutHalHidl() {
378 if (mStream != 0) {
Andy Hung638f45b2021-01-18 20:02:56 -0800379 if (mCallback.load().unsafe_get()) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800380 processReturn("clearCallback", mStream->clearCallback());
381 }
jiabinf6eb4c32020-02-25 14:06:25 -0800382#if MAJOR_VERSION >= 6
Andy Hung638f45b2021-01-18 20:02:56 -0800383 if (mEventCallback.load().unsafe_get() != nullptr) {
jiabinf6eb4c32020-02-25 14:06:25 -0800384 processReturn("setEventCallback",
385 mStream->setEventCallback(nullptr));
386 }
387#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800388 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800389 }
Andy Hung638f45b2021-01-18 20:02:56 -0800390 mCallback = nullptr;
391 mEventCallback = nullptr;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800392 if (mEfGroup) {
393 EventFlag::deleteEventFlag(&mEfGroup);
394 }
395}
396
397status_t StreamOutHalHidl::getFrameSize(size_t *size) {
Andy Hung224f82f2022-03-22 00:00:49 -0700398 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800399 if (mStream == 0) return NO_INIT;
400 return processReturn("getFrameSize", mStream->getFrameSize(), size);
401}
402
403status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
Andy Hung224f82f2022-03-22 00:00:49 -0700404 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800405 if (mStream == 0) return NO_INIT;
406 if (mWriterClient == gettid() && mCommandMQ) {
407 return callWriterThread(
408 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
409 [&](const WriteStatus& writeStatus) {
410 *latency = writeStatus.reply.latencyMs;
411 });
412 } else {
413 return processReturn("getLatency", mStream->getLatency(), latency);
414 }
415}
416
417status_t StreamOutHalHidl::setVolume(float left, float right) {
Andy Hung224f82f2022-03-22 00:00:49 -0700418 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800419 if (mStream == 0) return NO_INIT;
420 return processReturn("setVolume", mStream->setVolume(left, right));
421}
422
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800423#if MAJOR_VERSION == 2
424status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
Andy Hung224f82f2022-03-22 00:00:49 -0700425 TIME_CHECK();
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800426 if (mStream == 0) return NO_INIT;
427 std::vector<ParameterValue> parameters;
428 String8 halParameters;
429 parameters.push_back({AudioParameter::keyPresentationId, std::to_string(presentationId)});
430 parameters.push_back({AudioParameter::keyProgramId, std::to_string(programId)});
431 parametersToHal(hidl_vec<ParameterValue>(parameters), &halParameters);
432 return setParameters(halParameters);
433}
Kevin Rocard1cf6b4d2018-11-20 18:05:44 -0800434#elif MAJOR_VERSION >= 4
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800435status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
Andy Hung224f82f2022-03-22 00:00:49 -0700436 TIME_CHECK();
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800437 if (mStream == 0) return NO_INIT;
438 return processReturn("selectPresentation",
439 mStream->selectPresentation(presentationId, programId));
440}
441#endif
442
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800443status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
Shunkai Yaoc6308712023-02-22 17:53:04 +0000444 // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800445 if (mStream == 0) return NO_INIT;
446 *written = 0;
447
448 if (bytes == 0 && !mDataMQ) {
449 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
Andy Hung638f45b2021-01-18 20:02:56 -0800450 ALOGW_IF(mCallback.load().unsafe_get(), "First call to async write with 0 bytes");
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800451 return OK;
452 }
453
454 status_t status;
455 if (!mDataMQ) {
456 // In case if playback starts close to the end of a compressed track, the bytes
457 // that need to be written is less than the actual buffer size. Need to use
458 // full buffer size for the MQ since otherwise after seeking back to the middle
459 // data will be truncated.
460 size_t bufferSize;
461 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
462 return status;
463 }
464 if (bytes > bufferSize) bufferSize = bytes;
465 if ((status = prepareForWriting(bufferSize)) != OK) {
466 return status;
467 }
468 }
469
470 status = callWriterThread(
471 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
472 [&] (const WriteStatus& writeStatus) {
473 *written = writeStatus.reply.written;
474 // Diagnostics of the cause of b/35813113.
475 ALOGE_IF(*written > bytes,
476 "hal reports more bytes written than asked for: %lld > %lld",
477 (long long)*written, (long long)bytes);
478 });
479 mStreamPowerLog.log(buffer, *written);
480 return status;
481}
482
483status_t StreamOutHalHidl::callWriterThread(
484 WriteCommand cmd, const char* cmdName,
485 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
486 if (!mCommandMQ->write(&cmd)) {
487 ALOGE("command message queue write failed for \"%s\"", cmdName);
488 return -EAGAIN;
489 }
490 if (data != nullptr) {
491 size_t availableToWrite = mDataMQ->availableToWrite();
492 if (dataSize > availableToWrite) {
493 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
494 (long long)dataSize, (long long)availableToWrite);
495 dataSize = availableToWrite;
496 }
497 if (!mDataMQ->write(data, dataSize)) {
498 ALOGE("data message queue write failed for \"%s\"", cmdName);
499 }
500 }
501 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
502
503 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
504 uint32_t efState = 0;
505retry:
506 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
507 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
508 WriteStatus writeStatus;
509 writeStatus.retval = Result::NOT_INITIALIZED;
510 if (!mStatusMQ->read(&writeStatus)) {
511 ALOGE("status message read failed for \"%s\"", cmdName);
512 }
513 if (writeStatus.retval == Result::OK) {
514 ret = OK;
515 callback(writeStatus);
516 } else {
517 ret = processReturn(cmdName, writeStatus.retval);
518 }
519 return ret;
520 }
521 if (ret == -EAGAIN || ret == -EINTR) {
522 // Spurious wakeup. This normally retries no more than once.
523 goto retry;
524 }
525 return ret;
526}
527
528status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
529 std::unique_ptr<CommandMQ> tempCommandMQ;
530 std::unique_ptr<DataMQ> tempDataMQ;
531 std::unique_ptr<StatusMQ> tempStatusMQ;
532 Result retval;
533 pid_t halThreadPid, halThreadTid;
534 Return<void> ret = mStream->prepareForWriting(
535 1, bufferSize,
536 [&](Result r,
537 const CommandMQ::Descriptor& commandMQ,
538 const DataMQ::Descriptor& dataMQ,
539 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000540 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800541 retval = r;
542 if (retval == Result::OK) {
543 tempCommandMQ.reset(new CommandMQ(commandMQ));
544 tempDataMQ.reset(new DataMQ(dataMQ));
545 tempStatusMQ.reset(new StatusMQ(statusMQ));
546 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
547 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
548 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000549#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800550 halThreadPid = halThreadInfo.pid;
551 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000552#else
553 halThreadTid = halThreadInfo;
554#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800555 }
556 });
557 if (!ret.isOk() || retval != Result::OK) {
558 return processReturn("prepareForWriting", ret, retval);
559 }
560 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
561 !tempDataMQ || !tempDataMQ->isValid() ||
562 !tempStatusMQ || !tempStatusMQ->isValid() ||
563 !mEfGroup) {
564 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
565 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
566 "Command message queue for writing is invalid");
567 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
568 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
569 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
570 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
571 "Status message queue for writing is invalid");
572 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
573 return NO_INIT;
574 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000575#if MAJOR_VERSION >= 7
576 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
577 return status;
578 }
579#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800580 requestHalThreadPriority(halThreadPid, halThreadTid);
581
582 mCommandMQ = std::move(tempCommandMQ);
583 mDataMQ = std::move(tempDataMQ);
584 mStatusMQ = std::move(tempStatusMQ);
585 mWriterClient = gettid();
586 return OK;
587}
588
589status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
Shunkai Yaoc6308712023-02-22 17:53:04 +0000590 // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800591 if (mStream == 0) return NO_INIT;
592 Result retval;
593 Return<void> ret = mStream->getRenderPosition(
594 [&](Result r, uint32_t d) {
595 retval = r;
596 if (retval == Result::OK) {
597 *dspFrames = d;
598 }
599 });
600 return processReturn("getRenderPosition", ret, retval);
601}
602
603status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
Andy Hung224f82f2022-03-22 00:00:49 -0700604 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800605 if (mStream == 0) return NO_INIT;
606 Result retval;
607 Return<void> ret = mStream->getNextWriteTimestamp(
608 [&](Result r, int64_t t) {
609 retval = r;
610 if (retval == Result::OK) {
611 *timestamp = t;
612 }
613 });
614 return processReturn("getRenderPosition", ret, retval);
615}
616
617status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
Andy Hung224f82f2022-03-22 00:00:49 -0700618 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800619 if (mStream == 0) return NO_INIT;
620 status_t status = processReturn(
621 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
622 if (status == OK) {
623 mCallback = callback;
624 }
625 return status;
626}
627
628status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
Andy Hung224f82f2022-03-22 00:00:49 -0700629 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800630 if (mStream == 0) return NO_INIT;
631 Return<void> ret = mStream->supportsPauseAndResume(
632 [&](bool p, bool r) {
633 *supportsPause = p;
634 *supportsResume = r;
635 });
636 return processReturn("supportsPauseAndResume", ret);
637}
638
639status_t StreamOutHalHidl::pause() {
Andy Hung224f82f2022-03-22 00:00:49 -0700640 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800641 if (mStream == 0) return NO_INIT;
642 return processReturn("pause", mStream->pause());
643}
644
645status_t StreamOutHalHidl::resume() {
Andy Hung224f82f2022-03-22 00:00:49 -0700646 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800647 if (mStream == 0) return NO_INIT;
648 return processReturn("pause", mStream->resume());
649}
650
651status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
Andy Hung224f82f2022-03-22 00:00:49 -0700652 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800653 if (mStream == 0) return NO_INIT;
654 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
655}
656
657status_t StreamOutHalHidl::drain(bool earlyNotify) {
Andy Hung224f82f2022-03-22 00:00:49 -0700658 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800659 if (mStream == 0) return NO_INIT;
660 return processReturn(
661 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
662}
663
664status_t StreamOutHalHidl::flush() {
Andy Hung224f82f2022-03-22 00:00:49 -0700665 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800666 if (mStream == 0) return NO_INIT;
667 return processReturn("pause", mStream->flush());
668}
669
670status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
Shunkai Yaoc6308712023-02-22 17:53:04 +0000671 // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800672 if (mStream == 0) return NO_INIT;
673 if (mWriterClient == gettid() && mCommandMQ) {
674 return callWriterThread(
675 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
676 [&](const WriteStatus& writeStatus) {
677 *frames = writeStatus.reply.presentationPosition.frames;
678 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
679 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
680 });
681 } else {
682 Result retval;
683 Return<void> ret = mStream->getPresentationPosition(
684 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
685 retval = r;
686 if (retval == Result::OK) {
687 *frames = hidlFrames;
688 timestamp->tv_sec = hidlTimeStamp.tvSec;
689 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
690 }
691 });
692 return processReturn("getPresentationPosition", ret, retval);
693 }
694}
695
Kevin Rocard070e7512018-05-22 09:29:13 -0700696#if MAJOR_VERSION == 2
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800697status_t StreamOutHalHidl::updateSourceMetadata(
698 const StreamOutHalInterface::SourceMetadata& /* sourceMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700699 // Audio HAL V2.0 does not support propagating source metadata
700 return INVALID_OPERATION;
701}
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800702#elif MAJOR_VERSION >= 4
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800703status_t StreamOutHalHidl::updateSourceMetadata(
704 const StreamOutHalInterface::SourceMetadata& sourceMetadata) {
Andy Hung224f82f2022-03-22 00:00:49 -0700705 TIME_CHECK();
Mikhail Naganov6718c392022-01-27 22:17:21 +0000706#if MAJOR_VERSION == 4
707 ::android::hardware::audio::CORE_TYPES_CPP_VERSION::SourceMetadata hidlMetadata;
708#else
709 ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::SourceMetadata hidlMetadata;
710#endif
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000711 if (status_t status = CoreUtils::sourceMetadataFromHalV7(
712 sourceMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
713 status != OK) {
714 return status;
715 }
716 return processReturn("updateSourceMetadata", mStream->updateSourceMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -0700717}
Kevin Rocard070e7512018-05-22 09:29:13 -0700718#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700719
jiabinf6eb4c32020-02-25 14:06:25 -0800720#if MAJOR_VERSION < 6
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800721status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode __unused) {
722 return INVALID_OPERATION;
723}
724
725status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode __unused) {
726 return INVALID_OPERATION;
727}
728
729status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB __unused) {
730 return INVALID_OPERATION;
731}
732
733status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB __unused) {
734 return INVALID_OPERATION;
735}
736
737status_t StreamOutHalHidl::getPlaybackRateParameters(
738 audio_playback_rate_t* playbackRate __unused) {
739 return INVALID_OPERATION;
740}
741
742status_t StreamOutHalHidl::setPlaybackRateParameters(
743 const audio_playback_rate_t& playbackRate __unused) {
744 return INVALID_OPERATION;
745}
746
jiabinf6eb4c32020-02-25 14:06:25 -0800747status_t StreamOutHalHidl::setEventCallback(
748 const sp<StreamOutHalInterfaceEventCallback>& callback __unused) {
749 // Codec format callback is supported starting from audio HAL V6.0
750 return INVALID_OPERATION;
751}
Eric Laurentafa586b2022-01-27 21:10:55 +0100752
jiabinf6eb4c32020-02-25 14:06:25 -0800753#else
754
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800755status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode) {
Andy Hung224f82f2022-03-22 00:00:49 -0700756 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800757 if (mStream == 0) return NO_INIT;
758 Result retval;
759 Return<void> ret = mStream->getDualMonoMode(
760 [&](Result r, DualMonoMode hidlMode) {
761 retval = r;
762 if (retval == Result::OK) {
763 *mode = static_cast<audio_dual_mono_mode_t>(hidlMode);
764 }
765 });
766 return processReturn("getDualMonoMode", ret, retval);
767}
768
769status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode) {
Andy Hung224f82f2022-03-22 00:00:49 -0700770 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800771 if (mStream == 0) return NO_INIT;
772 return processReturn(
773 "setDualMonoMode", mStream->setDualMonoMode(static_cast<DualMonoMode>(mode)));
774}
775
776status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB) {
Andy Hung224f82f2022-03-22 00:00:49 -0700777 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800778 if (mStream == 0) return NO_INIT;
779 Result retval;
780 Return<void> ret = mStream->getAudioDescriptionMixLevel(
781 [&](Result r, float hidlLeveldB) {
782 retval = r;
783 if (retval == Result::OK) {
784 *leveldB = hidlLeveldB;
785 }
786 });
787 return processReturn("getAudioDescriptionMixLevel", ret, retval);
788}
789
790status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB) {
Andy Hung224f82f2022-03-22 00:00:49 -0700791 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800792 if (mStream == 0) return NO_INIT;
793 return processReturn(
794 "setAudioDescriptionMixLevel", mStream->setAudioDescriptionMixLevel(leveldB));
795}
796
797status_t StreamOutHalHidl::getPlaybackRateParameters(audio_playback_rate_t* playbackRate) {
Andy Hung224f82f2022-03-22 00:00:49 -0700798 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800799 if (mStream == 0) return NO_INIT;
800 Result retval;
801 Return<void> ret = mStream->getPlaybackRateParameters(
802 [&](Result r, PlaybackRate hidlPlaybackRate) {
803 retval = r;
804 if (retval == Result::OK) {
805 playbackRate->mSpeed = hidlPlaybackRate.speed;
806 playbackRate->mPitch = hidlPlaybackRate.pitch;
807 playbackRate->mStretchMode =
808 static_cast<audio_timestretch_stretch_mode_t>(
809 hidlPlaybackRate.timestretchMode);
810 playbackRate->mFallbackMode =
811 static_cast<audio_timestretch_fallback_mode_t>(
812 hidlPlaybackRate.fallbackMode);
813 }
814 });
815 return processReturn("getPlaybackRateParameters", ret, retval);
816}
817
818status_t StreamOutHalHidl::setPlaybackRateParameters(const audio_playback_rate_t& playbackRate) {
Andy Hung224f82f2022-03-22 00:00:49 -0700819 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800820 if (mStream == 0) return NO_INIT;
821 return processReturn(
822 "setPlaybackRateParameters", mStream->setPlaybackRateParameters(
823 PlaybackRate{playbackRate.mSpeed, playbackRate.mPitch,
824 static_cast<TimestretchMode>(playbackRate.mStretchMode),
825 static_cast<TimestretchFallbackMode>(playbackRate.mFallbackMode)}));
826}
827
Mikhail Naganov6718c392022-01-27 22:17:21 +0000828#include PATH(android/hardware/audio/CORE_TYPES_FILE_VERSION/IStreamOutEventCallback.h)
jiabinf6eb4c32020-02-25 14:06:25 -0800829
830namespace {
831
832struct StreamOutEventCallback : public IStreamOutEventCallback {
833 StreamOutEventCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
834
835 // IStreamOutEventCallback implementation
836 Return<void> onCodecFormatChanged(
837 const android::hardware::hidl_vec<uint8_t>& audioMetadata) override {
838 sp<StreamOutHalHidl> stream = mStream.promote();
839 if (stream != nullptr) {
840 std::basic_string<uint8_t> metadataBs(audioMetadata.begin(), audioMetadata.end());
841 stream->onCodecFormatChanged(metadataBs);
842 }
843 return Void();
844 }
845
846 private:
847 wp<StreamOutHalHidl> mStream;
848};
849
850} // namespace
851
852status_t StreamOutHalHidl::setEventCallback(
853 const sp<StreamOutHalInterfaceEventCallback>& callback) {
Andy Hung224f82f2022-03-22 00:00:49 -0700854 TIME_CHECK();
jiabinf6eb4c32020-02-25 14:06:25 -0800855 if (mStream == nullptr) return NO_INIT;
856 mEventCallback = callback;
857 status_t status = processReturn(
858 "setEventCallback",
859 mStream->setEventCallback(
860 callback.get() == nullptr ? nullptr : new StreamOutEventCallback(this)));
861 return status;
862}
863#endif
864
Eric Laurentafa586b2022-01-27 21:10:55 +0100865#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
866using hardware::audio::V7_1::LatencyMode;
867
868status_t StreamOutHalHidl::setLatencyMode(audio_latency_mode_t mode) {
Andy Hung224f82f2022-03-22 00:00:49 -0700869 TIME_CHECK();
Eric Laurentafa586b2022-01-27 21:10:55 +0100870 if (mStream == 0) return NO_INIT;
871 return processReturn(
872 "setLatencyMode", mStream->setLatencyMode(static_cast<LatencyMode>(mode)));
873};
874
875status_t StreamOutHalHidl::getRecommendedLatencyModes(std::vector<audio_latency_mode_t> *modes) {
Andy Hung224f82f2022-03-22 00:00:49 -0700876 TIME_CHECK();
Eric Laurentafa586b2022-01-27 21:10:55 +0100877 if (!mStream) return NO_INIT;
878 Result retval;
879 Return<void> ret = mStream->getRecommendedLatencyModes(
880 [&](Result r, hidl_vec<LatencyMode> hidlModes) {
881 retval = r;
882 for (size_t i = 0; i < hidlModes.size(); i++) {
883 modes->push_back(static_cast<audio_latency_mode_t>(hidlModes[i]));
884 }
885 });
886 return processReturn("getRecommendedLatencyModes", ret, retval);
887};
888
889#include PATH(android/hardware/audio/FILE_VERSION/IStreamOutLatencyModeCallback.h)
890
891using hardware::audio::V7_1::IStreamOutLatencyModeCallback;
892
893namespace {
894struct StreamOutLatencyModeCallback : public IStreamOutLatencyModeCallback {
895 StreamOutLatencyModeCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
896
897 // IStreamOutLatencyModeCallback implementation
898 Return<void> onRecommendedLatencyModeChanged(const hidl_vec<LatencyMode>& hidlModes) override {
899 sp<StreamOutHalHidl> stream = mStream.promote();
900 if (stream != nullptr) {
901 std::vector<audio_latency_mode_t> modes;
902 for (size_t i = 0; i < hidlModes.size(); i++) {
903 modes.push_back(static_cast<audio_latency_mode_t>(hidlModes[i]));
904 }
905 stream->onRecommendedLatencyModeChanged(modes);
906 }
907 return Void();
908 }
909
910 private:
911 wp<StreamOutHalHidl> mStream;
912};
913} // namespace
914
915status_t StreamOutHalHidl::setLatencyModeCallback(
916 const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) {
Andy Hung224f82f2022-03-22 00:00:49 -0700917 TIME_CHECK();
Eric Laurentafa586b2022-01-27 21:10:55 +0100918
919 if (mStream == nullptr) return NO_INIT;
920 mLatencyModeCallback = callback;
921 status_t status = processReturn(
922 "setLatencyModeCallback",
923 mStream->setLatencyModeCallback(
924 callback.get() == nullptr ? nullptr : new StreamOutLatencyModeCallback(this)));
925 return status;
926};
927
928#else
929
930status_t StreamOutHalHidl::setLatencyMode(audio_latency_mode_t mode __unused) {
931 return INVALID_OPERATION;
932};
933
934status_t StreamOutHalHidl::getRecommendedLatencyModes(
935 std::vector<audio_latency_mode_t> *modes __unused) {
936 return INVALID_OPERATION;
937};
938
939status_t StreamOutHalHidl::setLatencyModeCallback(
940 const sp<StreamOutHalInterfaceLatencyModeCallback>& callback __unused) {
941 return INVALID_OPERATION;
942};
943
944#endif
945
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800946void StreamOutHalHidl::onWriteReady() {
Andy Hung638f45b2021-01-18 20:02:56 -0800947 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800948 if (callback == 0) return;
949 ALOGV("asyncCallback onWriteReady");
950 callback->onWriteReady();
951}
952
953void StreamOutHalHidl::onDrainReady() {
Andy Hung638f45b2021-01-18 20:02:56 -0800954 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800955 if (callback == 0) return;
956 ALOGV("asyncCallback onDrainReady");
957 callback->onDrainReady();
958}
959
960void StreamOutHalHidl::onError() {
Andy Hung638f45b2021-01-18 20:02:56 -0800961 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800962 if (callback == 0) return;
963 ALOGV("asyncCallback onError");
964 callback->onError();
965}
966
jiabinf6eb4c32020-02-25 14:06:25 -0800967void StreamOutHalHidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) {
Andy Hung638f45b2021-01-18 20:02:56 -0800968 sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.load().promote();
jiabinf6eb4c32020-02-25 14:06:25 -0800969 if (callback == nullptr) return;
970 ALOGV("asyncCodecFormatCallback %s", __func__);
971 callback->onCodecFormatChanged(metadataBs);
972}
973
Eric Laurentafa586b2022-01-27 21:10:55 +0100974void StreamOutHalHidl::onRecommendedLatencyModeChanged(
975 const std::vector<audio_latency_mode_t>& modes) {
976 sp<StreamOutHalInterfaceLatencyModeCallback> callback = mLatencyModeCallback.load().promote();
977 if (callback == nullptr) return;
978 callback->onRecommendedLatencyModeChanged(modes);
979}
980
Ytai Ben-Tsvi7e0183f2022-02-04 10:49:54 -0800981status_t StreamOutHalHidl::exit() {
Mikhail Naganov0211cd92023-06-14 01:02:39 +0000982 // Signal exiting to HALs that use intermediate pipes to close them.
Andy Hungb72a5502023-03-27 15:53:06 -0700983 AudioParameter param;
984 param.addInt(String8(AudioParameter::keyExiting), 1);
Mikhail Naganov0211cd92023-06-14 01:02:39 +0000985 param.add(String8(AudioParameter::keyClosing), String8(AudioParameter::valueTrue));
Andy Hungb72a5502023-03-27 15:53:06 -0700986 return setParameters(param.toString());
Ytai Ben-Tsvi7e0183f2022-02-04 10:49:54 -0800987}
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800988
Mikhail Naganov6718c392022-01-27 22:17:21 +0000989StreamInHalHidl::StreamInHalHidl(
Mikhail Naganovaccbe8a2022-02-03 23:45:36 +0000990 const sp<::android::hardware::audio::CORE_TYPES_CPP_VERSION::IStreamIn>& stream)
Andy Hung224f82f2022-03-22 00:00:49 -0700991 : StreamHalHidl("StreamInHalHidl", stream.get())
992 , mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800993}
994
995StreamInHalHidl::~StreamInHalHidl() {
996 if (mStream != 0) {
997 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800998 }
999 if (mEfGroup) {
1000 EventFlag::deleteEventFlag(&mEfGroup);
1001 }
1002}
1003
1004status_t StreamInHalHidl::getFrameSize(size_t *size) {
Andy Hung224f82f2022-03-22 00:00:49 -07001005 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001006 if (mStream == 0) return NO_INIT;
1007 return processReturn("getFrameSize", mStream->getFrameSize(), size);
1008}
1009
1010status_t StreamInHalHidl::setGain(float gain) {
Andy Hung224f82f2022-03-22 00:00:49 -07001011 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001012 if (mStream == 0) return NO_INIT;
1013 return processReturn("setGain", mStream->setGain(gain));
1014}
1015
1016status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
Shunkai Yaoc6308712023-02-22 17:53:04 +00001017 // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001018 if (mStream == 0) return NO_INIT;
1019 *read = 0;
1020
1021 if (bytes == 0 && !mDataMQ) {
1022 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
1023 return OK;
1024 }
1025
1026 status_t status;
1027 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
1028 return status;
1029 }
1030
1031 ReadParameters params;
1032 params.command = ReadCommand::READ;
1033 params.params.read = bytes;
1034 status = callReaderThread(params, "read",
1035 [&](const ReadStatus& readStatus) {
1036 const size_t availToRead = mDataMQ->availableToRead();
1037 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
1038 ALOGE("data message queue read failed for \"read\"");
1039 }
1040 ALOGW_IF(availToRead != readStatus.reply.read,
1041 "HAL read report inconsistent: mq = %d, status = %d",
1042 (int32_t)availToRead, (int32_t)readStatus.reply.read);
1043 *read = readStatus.reply.read;
1044 });
1045 mStreamPowerLog.log(buffer, *read);
1046 return status;
1047}
1048
1049status_t StreamInHalHidl::callReaderThread(
1050 const ReadParameters& params, const char* cmdName,
1051 StreamInHalHidl::ReaderCallback callback) {
1052 if (!mCommandMQ->write(&params)) {
1053 ALOGW("command message queue write failed");
1054 return -EAGAIN;
1055 }
1056 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
1057
1058 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
1059 uint32_t efState = 0;
1060retry:
1061 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
1062 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
1063 ReadStatus readStatus;
1064 readStatus.retval = Result::NOT_INITIALIZED;
1065 if (!mStatusMQ->read(&readStatus)) {
1066 ALOGE("status message read failed for \"%s\"", cmdName);
1067 }
1068 if (readStatus.retval == Result::OK) {
1069 ret = OK;
1070 callback(readStatus);
1071 } else {
1072 ret = processReturn(cmdName, readStatus.retval);
1073 }
1074 return ret;
1075 }
1076 if (ret == -EAGAIN || ret == -EINTR) {
1077 // Spurious wakeup. This normally retries no more than once.
1078 goto retry;
1079 }
1080 return ret;
1081}
1082
1083status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
1084 std::unique_ptr<CommandMQ> tempCommandMQ;
1085 std::unique_ptr<DataMQ> tempDataMQ;
1086 std::unique_ptr<StatusMQ> tempStatusMQ;
1087 Result retval;
1088 pid_t halThreadPid, halThreadTid;
1089 Return<void> ret = mStream->prepareForReading(
1090 1, bufferSize,
1091 [&](Result r,
1092 const CommandMQ::Descriptor& commandMQ,
1093 const DataMQ::Descriptor& dataMQ,
1094 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001095 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001096 retval = r;
1097 if (retval == Result::OK) {
1098 tempCommandMQ.reset(new CommandMQ(commandMQ));
1099 tempDataMQ.reset(new DataMQ(dataMQ));
1100 tempStatusMQ.reset(new StatusMQ(statusMQ));
1101 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
1102 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
1103 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001104#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001105 halThreadPid = halThreadInfo.pid;
1106 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001107#else
1108 halThreadTid = halThreadInfo;
1109#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001110 }
1111 });
1112 if (!ret.isOk() || retval != Result::OK) {
1113 return processReturn("prepareForReading", ret, retval);
1114 }
1115 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
1116 !tempDataMQ || !tempDataMQ->isValid() ||
1117 !tempStatusMQ || !tempStatusMQ->isValid() ||
1118 !mEfGroup) {
1119 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
1120 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
1121 "Command message queue for writing is invalid");
1122 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
1123 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
1124 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
1125 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
1126 "Status message queue for reading is invalid");
1127 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
1128 return NO_INIT;
1129 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001130#if MAJOR_VERSION >= 7
1131 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
1132 return status;
1133 }
1134#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001135 requestHalThreadPriority(halThreadPid, halThreadTid);
1136
1137 mCommandMQ = std::move(tempCommandMQ);
1138 mDataMQ = std::move(tempDataMQ);
1139 mStatusMQ = std::move(tempStatusMQ);
1140 mReaderClient = gettid();
1141 return OK;
1142}
1143
1144status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
Andy Hung224f82f2022-03-22 00:00:49 -07001145 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001146 if (mStream == 0) return NO_INIT;
1147 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
1148}
1149
1150status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
Shunkai Yaoc6308712023-02-22 17:53:04 +00001151 // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001152 if (mStream == 0) return NO_INIT;
1153 if (mReaderClient == gettid() && mCommandMQ) {
1154 ReadParameters params;
1155 params.command = ReadCommand::GET_CAPTURE_POSITION;
1156 return callReaderThread(params, "getCapturePosition",
1157 [&](const ReadStatus& readStatus) {
1158 *frames = readStatus.reply.capturePosition.frames;
1159 *time = readStatus.reply.capturePosition.time;
1160 });
1161 } else {
1162 Result retval;
1163 Return<void> ret = mStream->getCapturePosition(
1164 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
1165 retval = r;
1166 if (retval == Result::OK) {
1167 *frames = hidlFrames;
1168 *time = hidlTime;
1169 }
1170 });
1171 return processReturn("getCapturePosition", ret, retval);
1172 }
1173}
1174
Kevin Rocard070e7512018-05-22 09:29:13 -07001175#if MAJOR_VERSION == 2
1176status_t StreamInHalHidl::getActiveMicrophones(
Mikhail Naganov2a6a3012023-02-13 11:45:03 -08001177 std::vector<media::MicrophoneInfoFw> *microphones __unused) {
Kevin Rocard070e7512018-05-22 09:29:13 -07001178 if (mStream == 0) return NO_INIT;
1179 return INVALID_OPERATION;
1180}
1181
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001182status_t StreamInHalHidl::updateSinkMetadata(
1183 const StreamInHalInterface::SinkMetadata& /* sinkMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -07001184 // Audio HAL V2.0 does not support propagating sink metadata
1185 return INVALID_OPERATION;
1186}
1187
Kevin Rocard3d48dce2018-11-08 17:16:57 -08001188#elif MAJOR_VERSION >= 4
jiabin9ff780e2018-03-19 18:19:52 -07001189status_t StreamInHalHidl::getActiveMicrophones(
Mikhail Naganov2a6a3012023-02-13 11:45:03 -08001190 std::vector<media::MicrophoneInfoFw> *microphonesInfo) {
Andy Hung224f82f2022-03-22 00:00:49 -07001191 TIME_CHECK();
jiabin9ff780e2018-03-19 18:19:52 -07001192 if (!mStream) return NO_INIT;
1193 Result retval;
1194 Return<void> ret = mStream->getActiveMicrophones(
1195 [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
1196 retval = r;
1197 for (size_t k = 0; k < micArrayHal.size(); k++) {
Mikhail Naganov2a6a3012023-02-13 11:45:03 -08001198 // Convert via legacy.
jiabin9ff780e2018-03-19 18:19:52 -07001199 audio_microphone_characteristic_t dst;
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001200 (void)CoreUtils::microphoneInfoToHal(micArrayHal[k], &dst);
Mikhail Naganov2a6a3012023-02-13 11:45:03 -08001201 auto conv = legacy2aidl_audio_microphone_characteristic_t_MicrophoneInfoFw(dst);
1202 if (conv.ok()) {
1203 microphonesInfo->push_back(conv.value());
1204 } else {
1205 ALOGW("getActiveMicrophones: could not convert %s to AIDL: %d",
1206 toString(micArrayHal[k]).c_str(), conv.error());
1207 microphonesInfo->push_back(media::MicrophoneInfoFw{});
1208 }
jiabin9ff780e2018-03-19 18:19:52 -07001209 }
1210 });
1211 return processReturn("getActiveMicrophones", ret, retval);
1212}
1213
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001214status_t StreamInHalHidl::updateSinkMetadata(const
1215 StreamInHalInterface::SinkMetadata& sinkMetadata) {
Andy Hung224f82f2022-03-22 00:00:49 -07001216 TIME_CHECK();
Mikhail Naganov6718c392022-01-27 22:17:21 +00001217#if MAJOR_VERSION == 4
1218 ::android::hardware::audio::CORE_TYPES_CPP_VERSION::SinkMetadata hidlMetadata;
1219#else
1220 ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::SinkMetadata hidlMetadata;
1221#endif
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001222 if (status_t status = CoreUtils::sinkMetadataFromHalV7(
1223 sinkMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
1224 status != OK) {
1225 return status;
1226 }
1227 return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -07001228}
Kevin Rocard070e7512018-05-22 09:29:13 -07001229#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -07001230
Paul McLean03a6e6a2018-12-04 10:54:13 -07001231#if MAJOR_VERSION < 5
Paul McLean12340082019-03-19 09:35:05 -06001232status_t StreamInHalHidl::setPreferredMicrophoneDirection(
1233 audio_microphone_direction_t direction __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001234 if (mStream == 0) return NO_INIT;
1235 return INVALID_OPERATION;
1236}
1237
Paul McLean12340082019-03-19 09:35:05 -06001238status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001239 if (mStream == 0) return NO_INIT;
1240 return INVALID_OPERATION;
1241}
1242#else
Paul McLean12340082019-03-19 09:35:05 -06001243status_t StreamInHalHidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
Andy Hung224f82f2022-03-22 00:00:49 -07001244 TIME_CHECK();
Paul McLean03a6e6a2018-12-04 10:54:13 -07001245 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001246 return processReturn("setPreferredMicrophoneDirection",
1247 mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction)));
Paul McLean03a6e6a2018-12-04 10:54:13 -07001248}
1249
Paul McLean12340082019-03-19 09:35:05 -06001250status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom) {
Andy Hung224f82f2022-03-22 00:00:49 -07001251 TIME_CHECK();
Paul McLean03a6e6a2018-12-04 10:54:13 -07001252 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001253 return processReturn("setPreferredMicrophoneFieldDimension",
Paul McLean03a6e6a2018-12-04 10:54:13 -07001254 mStream->setMicrophoneFieldDimension(zoom));
1255}
1256#endif
1257
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001258} // namespace android