blob: 07c6df519d6e5272670895592606270226052231 [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 Naganovd5d9de72023-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) {
Andy Hung308aaa52022-07-11 12:07:06 -0700444 // TIME_CHECK(); // TODO(b/238654698) 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) {
Andy Hung308aaa52022-07-11 12:07:06 -0700590 // TIME_CHECK(); // TODO(b/238654698) 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) {
Andy Hung308aaa52022-07-11 12:07:06 -0700671 // TIME_CHECK(); // TODO(b/238654698) 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() {
982 // FIXME this is using hard-coded strings but in the future, this functionality will be
983 // converted to use audio HAL extensions required to support tunneling
984 return setParameters(String8("exiting=1"));
985}
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800986
Mikhail Naganov6718c392022-01-27 22:17:21 +0000987StreamInHalHidl::StreamInHalHidl(
Mikhail Naganovaccbe8a2022-02-03 23:45:36 +0000988 const sp<::android::hardware::audio::CORE_TYPES_CPP_VERSION::IStreamIn>& stream)
Andy Hung224f82f2022-03-22 00:00:49 -0700989 : StreamHalHidl("StreamInHalHidl", stream.get())
990 , mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800991}
992
993StreamInHalHidl::~StreamInHalHidl() {
994 if (mStream != 0) {
995 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800996 }
997 if (mEfGroup) {
998 EventFlag::deleteEventFlag(&mEfGroup);
999 }
1000}
1001
1002status_t StreamInHalHidl::getFrameSize(size_t *size) {
Andy Hung224f82f2022-03-22 00:00:49 -07001003 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001004 if (mStream == 0) return NO_INIT;
1005 return processReturn("getFrameSize", mStream->getFrameSize(), size);
1006}
1007
1008status_t StreamInHalHidl::setGain(float gain) {
Andy Hung224f82f2022-03-22 00:00:49 -07001009 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001010 if (mStream == 0) return NO_INIT;
1011 return processReturn("setGain", mStream->setGain(gain));
1012}
1013
1014status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
Andy Hung308aaa52022-07-11 12:07:06 -07001015 // TIME_CHECK(); // TODO(b/238654698) reenable only when optimized.
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001016 if (mStream == 0) return NO_INIT;
1017 *read = 0;
1018
1019 if (bytes == 0 && !mDataMQ) {
1020 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
1021 return OK;
1022 }
1023
1024 status_t status;
1025 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
1026 return status;
1027 }
1028
1029 ReadParameters params;
1030 params.command = ReadCommand::READ;
1031 params.params.read = bytes;
1032 status = callReaderThread(params, "read",
1033 [&](const ReadStatus& readStatus) {
1034 const size_t availToRead = mDataMQ->availableToRead();
1035 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
1036 ALOGE("data message queue read failed for \"read\"");
1037 }
1038 ALOGW_IF(availToRead != readStatus.reply.read,
1039 "HAL read report inconsistent: mq = %d, status = %d",
1040 (int32_t)availToRead, (int32_t)readStatus.reply.read);
1041 *read = readStatus.reply.read;
1042 });
1043 mStreamPowerLog.log(buffer, *read);
1044 return status;
1045}
1046
1047status_t StreamInHalHidl::callReaderThread(
1048 const ReadParameters& params, const char* cmdName,
1049 StreamInHalHidl::ReaderCallback callback) {
1050 if (!mCommandMQ->write(&params)) {
1051 ALOGW("command message queue write failed");
1052 return -EAGAIN;
1053 }
1054 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
1055
1056 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
1057 uint32_t efState = 0;
1058retry:
1059 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
1060 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
1061 ReadStatus readStatus;
1062 readStatus.retval = Result::NOT_INITIALIZED;
1063 if (!mStatusMQ->read(&readStatus)) {
1064 ALOGE("status message read failed for \"%s\"", cmdName);
1065 }
1066 if (readStatus.retval == Result::OK) {
1067 ret = OK;
1068 callback(readStatus);
1069 } else {
1070 ret = processReturn(cmdName, readStatus.retval);
1071 }
1072 return ret;
1073 }
1074 if (ret == -EAGAIN || ret == -EINTR) {
1075 // Spurious wakeup. This normally retries no more than once.
1076 goto retry;
1077 }
1078 return ret;
1079}
1080
1081status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
1082 std::unique_ptr<CommandMQ> tempCommandMQ;
1083 std::unique_ptr<DataMQ> tempDataMQ;
1084 std::unique_ptr<StatusMQ> tempStatusMQ;
1085 Result retval;
1086 pid_t halThreadPid, halThreadTid;
1087 Return<void> ret = mStream->prepareForReading(
1088 1, bufferSize,
1089 [&](Result r,
1090 const CommandMQ::Descriptor& commandMQ,
1091 const DataMQ::Descriptor& dataMQ,
1092 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001093 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001094 retval = r;
1095 if (retval == Result::OK) {
1096 tempCommandMQ.reset(new CommandMQ(commandMQ));
1097 tempDataMQ.reset(new DataMQ(dataMQ));
1098 tempStatusMQ.reset(new StatusMQ(statusMQ));
1099 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
1100 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
1101 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001102#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001103 halThreadPid = halThreadInfo.pid;
1104 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001105#else
1106 halThreadTid = halThreadInfo;
1107#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001108 }
1109 });
1110 if (!ret.isOk() || retval != Result::OK) {
1111 return processReturn("prepareForReading", ret, retval);
1112 }
1113 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
1114 !tempDataMQ || !tempDataMQ->isValid() ||
1115 !tempStatusMQ || !tempStatusMQ->isValid() ||
1116 !mEfGroup) {
1117 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
1118 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
1119 "Command message queue for writing is invalid");
1120 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
1121 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
1122 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
1123 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
1124 "Status message queue for reading is invalid");
1125 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
1126 return NO_INIT;
1127 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001128#if MAJOR_VERSION >= 7
1129 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
1130 return status;
1131 }
1132#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001133 requestHalThreadPriority(halThreadPid, halThreadTid);
1134
1135 mCommandMQ = std::move(tempCommandMQ);
1136 mDataMQ = std::move(tempDataMQ);
1137 mStatusMQ = std::move(tempStatusMQ);
1138 mReaderClient = gettid();
1139 return OK;
1140}
1141
1142status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
Andy Hung224f82f2022-03-22 00:00:49 -07001143 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001144 if (mStream == 0) return NO_INIT;
1145 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
1146}
1147
1148status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
Andy Hung308aaa52022-07-11 12:07:06 -07001149 // TIME_CHECK(); // TODO(b/238654698) reenable only when optimized.
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001150 if (mStream == 0) return NO_INIT;
1151 if (mReaderClient == gettid() && mCommandMQ) {
1152 ReadParameters params;
1153 params.command = ReadCommand::GET_CAPTURE_POSITION;
1154 return callReaderThread(params, "getCapturePosition",
1155 [&](const ReadStatus& readStatus) {
1156 *frames = readStatus.reply.capturePosition.frames;
1157 *time = readStatus.reply.capturePosition.time;
1158 });
1159 } else {
1160 Result retval;
1161 Return<void> ret = mStream->getCapturePosition(
1162 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
1163 retval = r;
1164 if (retval == Result::OK) {
1165 *frames = hidlFrames;
1166 *time = hidlTime;
1167 }
1168 });
1169 return processReturn("getCapturePosition", ret, retval);
1170 }
1171}
1172
Kevin Rocard070e7512018-05-22 09:29:13 -07001173#if MAJOR_VERSION == 2
1174status_t StreamInHalHidl::getActiveMicrophones(
Mikhail Naganovd5d9de72023-02-13 11:45:03 -08001175 std::vector<media::MicrophoneInfoFw> *microphones __unused) {
Kevin Rocard070e7512018-05-22 09:29:13 -07001176 if (mStream == 0) return NO_INIT;
1177 return INVALID_OPERATION;
1178}
1179
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001180status_t StreamInHalHidl::updateSinkMetadata(
1181 const StreamInHalInterface::SinkMetadata& /* sinkMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -07001182 // Audio HAL V2.0 does not support propagating sink metadata
1183 return INVALID_OPERATION;
1184}
1185
Kevin Rocard3d48dce2018-11-08 17:16:57 -08001186#elif MAJOR_VERSION >= 4
jiabin9ff780e2018-03-19 18:19:52 -07001187status_t StreamInHalHidl::getActiveMicrophones(
Mikhail Naganovd5d9de72023-02-13 11:45:03 -08001188 std::vector<media::MicrophoneInfoFw> *microphonesInfo) {
Andy Hung224f82f2022-03-22 00:00:49 -07001189 TIME_CHECK();
jiabin9ff780e2018-03-19 18:19:52 -07001190 if (!mStream) return NO_INIT;
1191 Result retval;
1192 Return<void> ret = mStream->getActiveMicrophones(
1193 [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
1194 retval = r;
1195 for (size_t k = 0; k < micArrayHal.size(); k++) {
Mikhail Naganovd5d9de72023-02-13 11:45:03 -08001196 // Convert via legacy.
jiabin9ff780e2018-03-19 18:19:52 -07001197 audio_microphone_characteristic_t dst;
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001198 (void)CoreUtils::microphoneInfoToHal(micArrayHal[k], &dst);
Mikhail Naganovd5d9de72023-02-13 11:45:03 -08001199 auto conv = legacy2aidl_audio_microphone_characteristic_t_MicrophoneInfoFw(dst);
1200 if (conv.ok()) {
1201 microphonesInfo->push_back(conv.value());
1202 } else {
1203 ALOGW("getActiveMicrophones: could not convert %s to AIDL: %d",
1204 toString(micArrayHal[k]).c_str(), conv.error());
1205 microphonesInfo->push_back(media::MicrophoneInfoFw{});
1206 }
jiabin9ff780e2018-03-19 18:19:52 -07001207 }
1208 });
1209 return processReturn("getActiveMicrophones", ret, retval);
1210}
1211
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001212status_t StreamInHalHidl::updateSinkMetadata(const
1213 StreamInHalInterface::SinkMetadata& sinkMetadata) {
Andy Hung224f82f2022-03-22 00:00:49 -07001214 TIME_CHECK();
Mikhail Naganov6718c392022-01-27 22:17:21 +00001215#if MAJOR_VERSION == 4
1216 ::android::hardware::audio::CORE_TYPES_CPP_VERSION::SinkMetadata hidlMetadata;
1217#else
1218 ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::SinkMetadata hidlMetadata;
1219#endif
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001220 if (status_t status = CoreUtils::sinkMetadataFromHalV7(
1221 sinkMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
1222 status != OK) {
1223 return status;
1224 }
1225 return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -07001226}
Kevin Rocard070e7512018-05-22 09:29:13 -07001227#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -07001228
Paul McLean03a6e6a2018-12-04 10:54:13 -07001229#if MAJOR_VERSION < 5
Paul McLean12340082019-03-19 09:35:05 -06001230status_t StreamInHalHidl::setPreferredMicrophoneDirection(
1231 audio_microphone_direction_t direction __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001232 if (mStream == 0) return NO_INIT;
1233 return INVALID_OPERATION;
1234}
1235
Paul McLean12340082019-03-19 09:35:05 -06001236status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001237 if (mStream == 0) return NO_INIT;
1238 return INVALID_OPERATION;
1239}
1240#else
Paul McLean12340082019-03-19 09:35:05 -06001241status_t StreamInHalHidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
Andy Hung224f82f2022-03-22 00:00:49 -07001242 TIME_CHECK();
Paul McLean03a6e6a2018-12-04 10:54:13 -07001243 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001244 return processReturn("setPreferredMicrophoneDirection",
1245 mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction)));
Paul McLean03a6e6a2018-12-04 10:54:13 -07001246}
1247
Paul McLean12340082019-03-19 09:35:05 -06001248status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom) {
Andy Hung224f82f2022-03-22 00:00:49 -07001249 TIME_CHECK();
Paul McLean03a6e6a2018-12-04 10:54:13 -07001250 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001251 return processReturn("setPreferredMicrophoneFieldDimension",
Paul McLean03a6e6a2018-12-04 10:54:13 -07001252 mStream->setMicrophoneFieldDimension(zoom));
1253}
1254#endif
1255
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001256} // namespace android