blob: 72eadc604ce38fe887d9e0d2575a4cbc2f94a0e5 [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 Naganov89c22e42023-06-14 15:49:59 -070036#include "EffectHalHidl.h"
Mikhail Naganov247b5f92021-01-15 19:16:12 +000037#include "ParameterUtils.h"
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080038#include "StreamHalHidl.h"
39
Mikhail Naganov6718c392022-01-27 22:17:21 +000040using ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::implementation::HidlUtils;
41using ::android::hardware::audio::CORE_TYPES_CPP_VERSION::implementation::CoreUtils;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080042using ::android::hardware::MQDescriptorSync;
43using ::android::hardware::Return;
44using ::android::hardware::Void;
Kevin Rocarddf9b4202018-05-10 19:56:08 -070045
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080046namespace android {
47
Mikhail Naganovaccbe8a2022-02-03 23:45:36 +000048using ReadCommand = ::android::hardware::audio::CORE_TYPES_CPP_VERSION::IStreamIn::ReadCommand;
Mikhail Naganov9ccaa162018-12-12 10:27:29 -080049
Mikhail Naganov6718c392022-01-27 22:17:21 +000050using namespace ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION;
51using namespace ::android::hardware::audio::CORE_TYPES_CPP_VERSION;
Mikhail Naganov9ccaa162018-12-12 10:27:29 -080052
Andy Hung224f82f2022-03-22 00:00:49 -070053StreamHalHidl::StreamHalHidl(std::string_view className, IStream *stream)
Mikhail Naganov288a3432022-03-25 00:29:56 +000054 : CoreConversionHelperHidl(className),
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080055 mStream(stream),
56 mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT),
57 mCachedBufferSize(0){
58
59 // Instrument audio signal power logging.
60 // Note: This assumes channel mask, format, and sample rate do not change after creation.
Mikhail Naganov247b5f92021-01-15 19:16:12 +000061 audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
62 if (/* mStreamPowerLog.isUserDebugOrEngBuild() && */
Mikhail Naganov560637e2021-03-31 22:40:13 +000063 StreamHalHidl::getAudioProperties(&config) == NO_ERROR) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +000064 mStreamPowerLog.init(config.sample_rate, config.channel_mask, config.format);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080065 }
66}
67
Andy Hungacb5b982021-01-20 10:12:00 -080068StreamHalHidl::~StreamHalHidl() {
69 // The last step is to flush all binder commands so that the deletion
70 // of IStreamIn / IStreamOut (mStream) is issued with less delay. See b/35394629.
71 hardware::IPCThreadState::self()->flushCommands();
72}
73
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080074status_t StreamHalHidl::getBufferSize(size_t *size) {
Andy Hung224f82f2022-03-22 00:00:49 -070075 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080076 if (!mStream) return NO_INIT;
77 status_t status = processReturn("getBufferSize", mStream->getBufferSize(), size);
78 if (status == OK) {
79 mCachedBufferSize = *size;
80 }
81 return status;
82}
83
Mikhail Naganov560637e2021-03-31 22:40:13 +000084status_t StreamHalHidl::getAudioProperties(audio_config_base_t *configBase) {
Andy Hung224f82f2022-03-22 00:00:49 -070085 TIME_CHECK();
Mikhail Naganov560637e2021-03-31 22:40:13 +000086 *configBase = AUDIO_CONFIG_BASE_INITIALIZER;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080087 if (!mStream) return NO_INIT;
Mikhail Naganov247b5f92021-01-15 19:16:12 +000088#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080089 Return<void> ret = mStream->getAudioProperties(
Kevin Rocardb9cfbf12018-02-23 19:11:06 -080090 [&](uint32_t sr, auto m, auto f) {
Mikhail Naganov560637e2021-03-31 22:40:13 +000091 configBase->sample_rate = sr;
92 configBase->channel_mask = static_cast<audio_channel_mask_t>(m);
93 configBase->format = static_cast<audio_format_t>(f);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080094 });
95 return processReturn("getAudioProperties", ret);
Mikhail Naganov247b5f92021-01-15 19:16:12 +000096#else
97 Result retval;
98 status_t conversionStatus = BAD_VALUE;
Mikhail Naganov247b5f92021-01-15 19:16:12 +000099 Return<void> ret = mStream->getAudioProperties(
100 [&](Result r, const AudioConfigBase& config) {
101 retval = r;
102 if (retval == Result::OK) {
Mikhail Naganov560637e2021-03-31 22:40:13 +0000103 conversionStatus = HidlUtils::audioConfigBaseToHal(config, configBase);
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000104 }
105 });
106 if (status_t status = processReturn("getAudioProperties", ret, retval); status == NO_ERROR) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000107 return conversionStatus;
108 } else {
109 return status;
110 }
111#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800112}
113
114status_t StreamHalHidl::setParameters(const String8& kvPairs) {
Andy Hung224f82f2022-03-22 00:00:49 -0700115 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800116 if (!mStream) return NO_INIT;
117 hidl_vec<ParameterValue> hidlParams;
118 status_t status = parametersFromHal(kvPairs, &hidlParams);
119 if (status != OK) return status;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800120 return processReturn("setParameters",
Dean Wheatley7b417a22019-01-31 20:39:42 +1100121 utils::setParameters(mStream, {} /* context */, hidlParams));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800122}
123
124status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
Andy Hung224f82f2022-03-22 00:00:49 -0700125 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800126 values->clear();
127 if (!mStream) return NO_INIT;
128 hidl_vec<hidl_string> hidlKeys;
129 status_t status = keysFromHal(keys, &hidlKeys);
130 if (status != OK) return status;
131 Result retval;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800132 Return<void> ret = utils::getParameters(
133 mStream,
134 {} /* context */,
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800135 hidlKeys,
136 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
137 retval = r;
138 if (retval == Result::OK) {
139 parametersToHal(parameters, values);
140 }
141 });
142 return processReturn("getParameters", ret, retval);
143}
144
145status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
Andy Hung224f82f2022-03-22 00:00:49 -0700146 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800147 if (!mStream) return NO_INIT;
Mikhail Naganov89c22e42023-06-14 15:49:59 -0700148 auto hidlEffect = sp<effect::EffectHalHidl>::cast(effect);
149 return processReturn("addEffect", mStream->addEffect(hidlEffect->effectId()));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800150}
151
152status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
Andy Hung224f82f2022-03-22 00:00:49 -0700153 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800154 if (!mStream) return NO_INIT;
Mikhail Naganov89c22e42023-06-14 15:49:59 -0700155 auto hidlEffect = sp<effect::EffectHalHidl>::cast(effect);
156 return processReturn("removeEffect", mStream->removeEffect(hidlEffect->effectId()));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800157}
158
159status_t StreamHalHidl::standby() {
Andy Hung224f82f2022-03-22 00:00:49 -0700160 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800161 if (!mStream) return NO_INIT;
162 return processReturn("standby", mStream->standby());
163}
164
Andy Hung61589a42021-06-16 09:37:53 -0700165status_t StreamHalHidl::dump(int fd, const Vector<String16>& args) {
Andy Hung224f82f2022-03-22 00:00:49 -0700166 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800167 if (!mStream) return NO_INIT;
168 native_handle_t* hidlHandle = native_handle_create(1, 0);
169 hidlHandle->data[0] = fd;
Andy Hung61589a42021-06-16 09:37:53 -0700170 hidl_vec<hidl_string> hidlArgs;
171 argsFromHal(args, &hidlArgs);
172 Return<void> ret = mStream->debug(hidlHandle, hidlArgs);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800173 native_handle_delete(hidlHandle);
Andy Hunge72ff022021-08-16 10:16:15 -0700174
175 // TODO(b/111997867, b/177271958) Workaround - remove when fixed.
176 // A Binder transmitted fd may not close immediately due to a race condition b/111997867
177 // when the remote binder thread removes the last refcount to the fd blocks in the
178 // kernel for binder activity. We send a Binder ping() command to unblock the thread
179 // and complete the fd close / release.
180 //
181 // See DeviceHalHidl::dump(), EffectHalHidl::dump(), StreamHalHidl::dump(),
182 // EffectsFactoryHalHidl::dumpEffects().
183
184 (void)mStream->ping(); // synchronous Binder call
185
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800186 mStreamPowerLog.dump(fd);
187 return processReturn("dump", ret);
188}
189
190status_t StreamHalHidl::start() {
Andy Hung224f82f2022-03-22 00:00:49 -0700191 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800192 if (!mStream) return NO_INIT;
193 return processReturn("start", mStream->start());
194}
195
196status_t StreamHalHidl::stop() {
Andy Hung224f82f2022-03-22 00:00:49 -0700197 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800198 if (!mStream) return NO_INIT;
199 return processReturn("stop", mStream->stop());
200}
201
202status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
203 struct audio_mmap_buffer_info *info) {
Andy Hung224f82f2022-03-22 00:00:49 -0700204 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800205 Result retval;
206 Return<void> ret = mStream->createMmapBuffer(
207 minSizeFrames,
208 [&](Result r, const MmapBufferInfo& hidlInfo) {
209 retval = r;
210 if (retval == Result::OK) {
211 const native_handle *handle = hidlInfo.sharedMemory.handle();
212 if (handle->numFds > 0) {
213 info->shared_memory_fd = handle->data[0];
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800214#if MAJOR_VERSION >= 4
Kevin Rocard734334f2018-07-12 19:37:41 -0700215 info->flags = audio_mmap_buffer_flag(hidlInfo.flags);
216#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800217 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
Kevin Rocard734334f2018-07-12 19:37:41 -0700218 // Negative buffer size frame was a hack in O and P to
219 // indicate that the buffer is shareable to applications
220 if (info->buffer_size_frames < 0) {
221 info->buffer_size_frames *= -1;
222 info->flags = audio_mmap_buffer_flag(
223 info->flags | AUDIO_MMAP_APPLICATION_SHAREABLE);
224 }
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800225 info->burst_size_frames = hidlInfo.burstSizeFrames;
226 // info->shared_memory_address is not needed in HIDL context
227 info->shared_memory_address = NULL;
228 } else {
229 retval = Result::NOT_INITIALIZED;
230 }
231 }
232 });
233 return processReturn("createMmapBuffer", ret, retval);
234}
235
236status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
Andy Hung224f82f2022-03-22 00:00:49 -0700237 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800238 Result retval;
239 Return<void> ret = mStream->getMmapPosition(
240 [&](Result r, const MmapPosition& hidlPosition) {
241 retval = r;
242 if (retval == Result::OK) {
243 position->time_nanoseconds = hidlPosition.timeNanoseconds;
244 position->position_frames = hidlPosition.positionFrames;
245 }
246 });
247 return processReturn("getMmapPosition", ret, retval);
248}
249
250status_t StreamHalHidl::setHalThreadPriority(int priority) {
251 mHalThreadPriority = priority;
252 return OK;
253}
254
255status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
256 if (mCachedBufferSize != 0) {
257 *size = mCachedBufferSize;
258 return OK;
259 }
260 return getBufferSize(size);
261}
262
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000263status_t StreamHalHidl::getHalPid(pid_t *pid) {
264 using ::android::hidl::base::V1_0::DebugInfo;
265 using ::android::hidl::manager::V1_0::IServiceManager;
Andy Hung224f82f2022-03-22 00:00:49 -0700266 TIME_CHECK();
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000267 DebugInfo debugInfo;
268 auto ret = mStream->getDebugInfo([&] (const auto &info) {
269 debugInfo = info;
270 });
271 if (!ret.isOk()) {
272 return INVALID_OPERATION;
273 }
274 if (debugInfo.pid != (int)IServiceManager::PidConstant::NO_PID) {
275 *pid = debugInfo.pid;
276 return NO_ERROR;
277 }
278 return NAME_NOT_FOUND;
279}
280
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800281bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
282 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
283 return true;
284 }
285 int err = requestPriority(
286 threadPid, threadId,
287 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
288 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
289 mHalThreadPriority, threadPid, threadId, err);
290 // Audio will still work, but latency will be higher and sometimes unacceptable.
291 return err == 0;
292}
293
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800294status_t StreamHalHidl::legacyCreateAudioPatch(const struct audio_port_config& port,
295 std::optional<audio_source_t> source,
296 audio_devices_t type) {
Andy Hung224f82f2022-03-22 00:00:49 -0700297 TIME_CHECK();
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800298 LOG_ALWAYS_FATAL_IF(port.type != AUDIO_PORT_TYPE_DEVICE, "port type must be device");
Ytai Ben-Tsvidb6f8982022-02-07 12:06:23 -0800299 unique_malloced_ptr<char> address;
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800300 if (strcmp(port.ext.device.address, "") != 0) {
301 // FIXME: we only support address on first sink with HAL version < 3.0
Ytai Ben-Tsvidb6f8982022-02-07 12:06:23 -0800302 address.reset(
303 audio_device_address_to_parameter(port.ext.device.type, port.ext.device.address));
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800304 } else {
Ytai Ben-Tsvidb6f8982022-02-07 12:06:23 -0800305 address.reset((char*)calloc(1, 1));
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800306 }
Ytai Ben-Tsvidb6f8982022-02-07 12:06:23 -0800307 AudioParameter param = AudioParameter(String8(address.get()));
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800308 param.addInt(String8(AudioParameter::keyRouting), (int)type);
309 if (source.has_value()) {
310 param.addInt(String8(AudioParameter::keyInputSource), (int)source.value());
311 }
312 return setParameters(param.toString());
313}
314
315status_t StreamHalHidl::legacyReleaseAudioPatch() {
Andy Hung224f82f2022-03-22 00:00:49 -0700316 TIME_CHECK();
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800317 AudioParameter param;
318 param.addInt(String8(AudioParameter::keyRouting), 0);
319 return setParameters(param.toString());
320}
321
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800322namespace {
323
324/* Notes on callback ownership.
325
326This is how (Hw)Binder ownership model looks like. The server implementation
327is owned by Binder framework (via sp<>). Proxies are owned by clients.
328When the last proxy disappears, Binder framework releases the server impl.
329
330Thus, it is not needed to keep any references to StreamOutCallback (this is
331the server impl) -- it will live as long as HAL server holds a strong ref to
332IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
333from the destructor of StreamOutHalHidl.
334
335The callback only keeps a weak reference to the stream. The stream is owned
336by AudioFlinger.
337
338*/
339
340struct StreamOutCallback : public IStreamOutCallback {
341 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
342
343 // IStreamOutCallback implementation
344 Return<void> onWriteReady() override {
345 sp<StreamOutHalHidl> stream = mStream.promote();
346 if (stream != 0) {
347 stream->onWriteReady();
348 }
349 return Void();
350 }
351
352 Return<void> onDrainReady() override {
353 sp<StreamOutHalHidl> stream = mStream.promote();
354 if (stream != 0) {
355 stream->onDrainReady();
356 }
357 return Void();
358 }
359
360 Return<void> onError() override {
361 sp<StreamOutHalHidl> stream = mStream.promote();
362 if (stream != 0) {
363 stream->onError();
364 }
365 return Void();
366 }
367
368 private:
Andy Hung638f45b2021-01-18 20:02:56 -0800369 const wp<StreamOutHalHidl> mStream;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800370};
371
372} // namespace
373
Mikhail Naganov6718c392022-01-27 22:17:21 +0000374StreamOutHalHidl::StreamOutHalHidl(
375 const sp<::android::hardware::audio::CPP_VERSION::IStreamOut>& stream)
Andy Hung224f82f2022-03-22 00:00:49 -0700376 : StreamHalHidl("StreamOutHalHidl", stream.get())
377 , mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800378}
379
380StreamOutHalHidl::~StreamOutHalHidl() {
381 if (mStream != 0) {
Andy Hung638f45b2021-01-18 20:02:56 -0800382 if (mCallback.load().unsafe_get()) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800383 processReturn("clearCallback", mStream->clearCallback());
384 }
jiabinf6eb4c32020-02-25 14:06:25 -0800385#if MAJOR_VERSION >= 6
Andy Hung638f45b2021-01-18 20:02:56 -0800386 if (mEventCallback.load().unsafe_get() != nullptr) {
jiabinf6eb4c32020-02-25 14:06:25 -0800387 processReturn("setEventCallback",
388 mStream->setEventCallback(nullptr));
389 }
390#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800391 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800392 }
Andy Hung638f45b2021-01-18 20:02:56 -0800393 mCallback = nullptr;
394 mEventCallback = nullptr;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800395 if (mEfGroup) {
396 EventFlag::deleteEventFlag(&mEfGroup);
397 }
398}
399
400status_t StreamOutHalHidl::getFrameSize(size_t *size) {
Andy Hung224f82f2022-03-22 00:00:49 -0700401 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800402 if (mStream == 0) return NO_INIT;
403 return processReturn("getFrameSize", mStream->getFrameSize(), size);
404}
405
406status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
Andy Hung224f82f2022-03-22 00:00:49 -0700407 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800408 if (mStream == 0) return NO_INIT;
409 if (mWriterClient == gettid() && mCommandMQ) {
410 return callWriterThread(
411 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
412 [&](const WriteStatus& writeStatus) {
413 *latency = writeStatus.reply.latencyMs;
414 });
415 } else {
416 return processReturn("getLatency", mStream->getLatency(), latency);
417 }
418}
419
420status_t StreamOutHalHidl::setVolume(float left, float right) {
Andy Hung224f82f2022-03-22 00:00:49 -0700421 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800422 if (mStream == 0) return NO_INIT;
423 return processReturn("setVolume", mStream->setVolume(left, right));
424}
425
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800426#if MAJOR_VERSION == 2
427status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
Andy Hung224f82f2022-03-22 00:00:49 -0700428 TIME_CHECK();
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800429 if (mStream == 0) return NO_INIT;
430 std::vector<ParameterValue> parameters;
431 String8 halParameters;
432 parameters.push_back({AudioParameter::keyPresentationId, std::to_string(presentationId)});
433 parameters.push_back({AudioParameter::keyProgramId, std::to_string(programId)});
434 parametersToHal(hidl_vec<ParameterValue>(parameters), &halParameters);
435 return setParameters(halParameters);
436}
Kevin Rocard1cf6b4d2018-11-20 18:05:44 -0800437#elif MAJOR_VERSION >= 4
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800438status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
Andy Hung224f82f2022-03-22 00:00:49 -0700439 TIME_CHECK();
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800440 if (mStream == 0) return NO_INIT;
441 return processReturn("selectPresentation",
442 mStream->selectPresentation(presentationId, programId));
443}
444#endif
445
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800446status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
Shunkai Yaoc6308712023-02-22 17:53:04 +0000447 // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800448 if (mStream == 0) return NO_INIT;
449 *written = 0;
450
451 if (bytes == 0 && !mDataMQ) {
452 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
Andy Hung638f45b2021-01-18 20:02:56 -0800453 ALOGW_IF(mCallback.load().unsafe_get(), "First call to async write with 0 bytes");
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800454 return OK;
455 }
456
457 status_t status;
458 if (!mDataMQ) {
459 // In case if playback starts close to the end of a compressed track, the bytes
460 // that need to be written is less than the actual buffer size. Need to use
461 // full buffer size for the MQ since otherwise after seeking back to the middle
462 // data will be truncated.
463 size_t bufferSize;
464 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
465 return status;
466 }
467 if (bytes > bufferSize) bufferSize = bytes;
468 if ((status = prepareForWriting(bufferSize)) != OK) {
469 return status;
470 }
471 }
472
473 status = callWriterThread(
474 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
475 [&] (const WriteStatus& writeStatus) {
476 *written = writeStatus.reply.written;
477 // Diagnostics of the cause of b/35813113.
478 ALOGE_IF(*written > bytes,
479 "hal reports more bytes written than asked for: %lld > %lld",
480 (long long)*written, (long long)bytes);
481 });
482 mStreamPowerLog.log(buffer, *written);
483 return status;
484}
485
486status_t StreamOutHalHidl::callWriterThread(
487 WriteCommand cmd, const char* cmdName,
488 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
489 if (!mCommandMQ->write(&cmd)) {
490 ALOGE("command message queue write failed for \"%s\"", cmdName);
491 return -EAGAIN;
492 }
493 if (data != nullptr) {
494 size_t availableToWrite = mDataMQ->availableToWrite();
495 if (dataSize > availableToWrite) {
496 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
497 (long long)dataSize, (long long)availableToWrite);
498 dataSize = availableToWrite;
499 }
500 if (!mDataMQ->write(data, dataSize)) {
501 ALOGE("data message queue write failed for \"%s\"", cmdName);
502 }
503 }
504 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
505
506 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
507 uint32_t efState = 0;
508retry:
509 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
510 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
511 WriteStatus writeStatus;
512 writeStatus.retval = Result::NOT_INITIALIZED;
513 if (!mStatusMQ->read(&writeStatus)) {
514 ALOGE("status message read failed for \"%s\"", cmdName);
515 }
516 if (writeStatus.retval == Result::OK) {
517 ret = OK;
518 callback(writeStatus);
519 } else {
520 ret = processReturn(cmdName, writeStatus.retval);
521 }
522 return ret;
523 }
524 if (ret == -EAGAIN || ret == -EINTR) {
525 // Spurious wakeup. This normally retries no more than once.
526 goto retry;
527 }
528 return ret;
529}
530
531status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
532 std::unique_ptr<CommandMQ> tempCommandMQ;
533 std::unique_ptr<DataMQ> tempDataMQ;
534 std::unique_ptr<StatusMQ> tempStatusMQ;
535 Result retval;
536 pid_t halThreadPid, halThreadTid;
537 Return<void> ret = mStream->prepareForWriting(
538 1, bufferSize,
539 [&](Result r,
540 const CommandMQ::Descriptor& commandMQ,
541 const DataMQ::Descriptor& dataMQ,
542 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000543 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800544 retval = r;
545 if (retval == Result::OK) {
546 tempCommandMQ.reset(new CommandMQ(commandMQ));
547 tempDataMQ.reset(new DataMQ(dataMQ));
548 tempStatusMQ.reset(new StatusMQ(statusMQ));
549 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
550 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
551 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000552#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800553 halThreadPid = halThreadInfo.pid;
554 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000555#else
556 halThreadTid = halThreadInfo;
557#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800558 }
559 });
560 if (!ret.isOk() || retval != Result::OK) {
561 return processReturn("prepareForWriting", ret, retval);
562 }
563 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
564 !tempDataMQ || !tempDataMQ->isValid() ||
565 !tempStatusMQ || !tempStatusMQ->isValid() ||
566 !mEfGroup) {
567 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
568 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
569 "Command message queue for writing is invalid");
570 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
571 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
572 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
573 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
574 "Status message queue for writing is invalid");
575 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
576 return NO_INIT;
577 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000578#if MAJOR_VERSION >= 7
579 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
580 return status;
581 }
582#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800583 requestHalThreadPriority(halThreadPid, halThreadTid);
584
585 mCommandMQ = std::move(tempCommandMQ);
586 mDataMQ = std::move(tempDataMQ);
587 mStatusMQ = std::move(tempStatusMQ);
588 mWriterClient = gettid();
589 return OK;
590}
591
592status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
Shunkai Yaoc6308712023-02-22 17:53:04 +0000593 // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800594 if (mStream == 0) return NO_INIT;
595 Result retval;
596 Return<void> ret = mStream->getRenderPosition(
597 [&](Result r, uint32_t d) {
598 retval = r;
599 if (retval == Result::OK) {
600 *dspFrames = d;
601 }
602 });
603 return processReturn("getRenderPosition", ret, retval);
604}
605
606status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
Andy Hung224f82f2022-03-22 00:00:49 -0700607 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800608 if (mStream == 0) return NO_INIT;
609 Result retval;
610 Return<void> ret = mStream->getNextWriteTimestamp(
611 [&](Result r, int64_t t) {
612 retval = r;
613 if (retval == Result::OK) {
614 *timestamp = t;
615 }
616 });
617 return processReturn("getRenderPosition", ret, retval);
618}
619
620status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
Andy Hung224f82f2022-03-22 00:00:49 -0700621 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800622 if (mStream == 0) return NO_INIT;
623 status_t status = processReturn(
624 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
625 if (status == OK) {
626 mCallback = callback;
627 }
628 return status;
629}
630
631status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
Andy Hung224f82f2022-03-22 00:00:49 -0700632 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800633 if (mStream == 0) return NO_INIT;
634 Return<void> ret = mStream->supportsPauseAndResume(
635 [&](bool p, bool r) {
636 *supportsPause = p;
637 *supportsResume = r;
638 });
639 return processReturn("supportsPauseAndResume", ret);
640}
641
642status_t StreamOutHalHidl::pause() {
Andy Hung224f82f2022-03-22 00:00:49 -0700643 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800644 if (mStream == 0) return NO_INIT;
645 return processReturn("pause", mStream->pause());
646}
647
648status_t StreamOutHalHidl::resume() {
Andy Hung224f82f2022-03-22 00:00:49 -0700649 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800650 if (mStream == 0) return NO_INIT;
651 return processReturn("pause", mStream->resume());
652}
653
654status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
Andy Hung224f82f2022-03-22 00:00:49 -0700655 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800656 if (mStream == 0) return NO_INIT;
657 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
658}
659
660status_t StreamOutHalHidl::drain(bool earlyNotify) {
Andy Hung224f82f2022-03-22 00:00:49 -0700661 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800662 if (mStream == 0) return NO_INIT;
663 return processReturn(
664 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
665}
666
667status_t StreamOutHalHidl::flush() {
Andy Hung224f82f2022-03-22 00:00:49 -0700668 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800669 if (mStream == 0) return NO_INIT;
670 return processReturn("pause", mStream->flush());
671}
672
673status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
Shunkai Yaoc6308712023-02-22 17:53:04 +0000674 // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800675 if (mStream == 0) return NO_INIT;
676 if (mWriterClient == gettid() && mCommandMQ) {
677 return callWriterThread(
678 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
679 [&](const WriteStatus& writeStatus) {
680 *frames = writeStatus.reply.presentationPosition.frames;
681 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
682 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
683 });
684 } else {
685 Result retval;
686 Return<void> ret = mStream->getPresentationPosition(
687 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
688 retval = r;
689 if (retval == Result::OK) {
690 *frames = hidlFrames;
691 timestamp->tv_sec = hidlTimeStamp.tvSec;
692 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
693 }
694 });
695 return processReturn("getPresentationPosition", ret, retval);
696 }
697}
698
Kevin Rocard070e7512018-05-22 09:29:13 -0700699#if MAJOR_VERSION == 2
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800700status_t StreamOutHalHidl::updateSourceMetadata(
701 const StreamOutHalInterface::SourceMetadata& /* sourceMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700702 // Audio HAL V2.0 does not support propagating source metadata
703 return INVALID_OPERATION;
704}
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800705#elif MAJOR_VERSION >= 4
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800706status_t StreamOutHalHidl::updateSourceMetadata(
707 const StreamOutHalInterface::SourceMetadata& sourceMetadata) {
Andy Hung224f82f2022-03-22 00:00:49 -0700708 TIME_CHECK();
Mikhail Naganov6718c392022-01-27 22:17:21 +0000709#if MAJOR_VERSION == 4
710 ::android::hardware::audio::CORE_TYPES_CPP_VERSION::SourceMetadata hidlMetadata;
711#else
712 ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::SourceMetadata hidlMetadata;
713#endif
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000714 if (status_t status = CoreUtils::sourceMetadataFromHalV7(
715 sourceMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
716 status != OK) {
717 return status;
718 }
719 return processReturn("updateSourceMetadata", mStream->updateSourceMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -0700720}
Kevin Rocard070e7512018-05-22 09:29:13 -0700721#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700722
jiabinf6eb4c32020-02-25 14:06:25 -0800723#if MAJOR_VERSION < 6
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800724status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode __unused) {
725 return INVALID_OPERATION;
726}
727
728status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode __unused) {
729 return INVALID_OPERATION;
730}
731
732status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB __unused) {
733 return INVALID_OPERATION;
734}
735
736status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB __unused) {
737 return INVALID_OPERATION;
738}
739
740status_t StreamOutHalHidl::getPlaybackRateParameters(
741 audio_playback_rate_t* playbackRate __unused) {
742 return INVALID_OPERATION;
743}
744
745status_t StreamOutHalHidl::setPlaybackRateParameters(
746 const audio_playback_rate_t& playbackRate __unused) {
747 return INVALID_OPERATION;
748}
749
jiabinf6eb4c32020-02-25 14:06:25 -0800750status_t StreamOutHalHidl::setEventCallback(
751 const sp<StreamOutHalInterfaceEventCallback>& callback __unused) {
752 // Codec format callback is supported starting from audio HAL V6.0
753 return INVALID_OPERATION;
754}
Eric Laurentafa586b2022-01-27 21:10:55 +0100755
jiabinf6eb4c32020-02-25 14:06:25 -0800756#else
757
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800758status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode) {
Andy Hung224f82f2022-03-22 00:00:49 -0700759 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800760 if (mStream == 0) return NO_INIT;
761 Result retval;
762 Return<void> ret = mStream->getDualMonoMode(
763 [&](Result r, DualMonoMode hidlMode) {
764 retval = r;
765 if (retval == Result::OK) {
766 *mode = static_cast<audio_dual_mono_mode_t>(hidlMode);
767 }
768 });
769 return processReturn("getDualMonoMode", ret, retval);
770}
771
772status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode) {
Andy Hung224f82f2022-03-22 00:00:49 -0700773 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800774 if (mStream == 0) return NO_INIT;
775 return processReturn(
776 "setDualMonoMode", mStream->setDualMonoMode(static_cast<DualMonoMode>(mode)));
777}
778
779status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB) {
Andy Hung224f82f2022-03-22 00:00:49 -0700780 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800781 if (mStream == 0) return NO_INIT;
782 Result retval;
783 Return<void> ret = mStream->getAudioDescriptionMixLevel(
784 [&](Result r, float hidlLeveldB) {
785 retval = r;
786 if (retval == Result::OK) {
787 *leveldB = hidlLeveldB;
788 }
789 });
790 return processReturn("getAudioDescriptionMixLevel", ret, retval);
791}
792
793status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB) {
Andy Hung224f82f2022-03-22 00:00:49 -0700794 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800795 if (mStream == 0) return NO_INIT;
796 return processReturn(
797 "setAudioDescriptionMixLevel", mStream->setAudioDescriptionMixLevel(leveldB));
798}
799
800status_t StreamOutHalHidl::getPlaybackRateParameters(audio_playback_rate_t* playbackRate) {
Andy Hung224f82f2022-03-22 00:00:49 -0700801 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800802 if (mStream == 0) return NO_INIT;
803 Result retval;
804 Return<void> ret = mStream->getPlaybackRateParameters(
805 [&](Result r, PlaybackRate hidlPlaybackRate) {
806 retval = r;
807 if (retval == Result::OK) {
808 playbackRate->mSpeed = hidlPlaybackRate.speed;
809 playbackRate->mPitch = hidlPlaybackRate.pitch;
810 playbackRate->mStretchMode =
811 static_cast<audio_timestretch_stretch_mode_t>(
812 hidlPlaybackRate.timestretchMode);
813 playbackRate->mFallbackMode =
814 static_cast<audio_timestretch_fallback_mode_t>(
815 hidlPlaybackRate.fallbackMode);
816 }
817 });
818 return processReturn("getPlaybackRateParameters", ret, retval);
819}
820
821status_t StreamOutHalHidl::setPlaybackRateParameters(const audio_playback_rate_t& playbackRate) {
Andy Hung224f82f2022-03-22 00:00:49 -0700822 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800823 if (mStream == 0) return NO_INIT;
824 return processReturn(
825 "setPlaybackRateParameters", mStream->setPlaybackRateParameters(
826 PlaybackRate{playbackRate.mSpeed, playbackRate.mPitch,
827 static_cast<TimestretchMode>(playbackRate.mStretchMode),
828 static_cast<TimestretchFallbackMode>(playbackRate.mFallbackMode)}));
829}
830
Mikhail Naganov6718c392022-01-27 22:17:21 +0000831#include PATH(android/hardware/audio/CORE_TYPES_FILE_VERSION/IStreamOutEventCallback.h)
jiabinf6eb4c32020-02-25 14:06:25 -0800832
833namespace {
834
835struct StreamOutEventCallback : public IStreamOutEventCallback {
836 StreamOutEventCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
837
838 // IStreamOutEventCallback implementation
839 Return<void> onCodecFormatChanged(
840 const android::hardware::hidl_vec<uint8_t>& audioMetadata) override {
841 sp<StreamOutHalHidl> stream = mStream.promote();
842 if (stream != nullptr) {
843 std::basic_string<uint8_t> metadataBs(audioMetadata.begin(), audioMetadata.end());
844 stream->onCodecFormatChanged(metadataBs);
845 }
846 return Void();
847 }
848
849 private:
850 wp<StreamOutHalHidl> mStream;
851};
852
853} // namespace
854
855status_t StreamOutHalHidl::setEventCallback(
856 const sp<StreamOutHalInterfaceEventCallback>& callback) {
Andy Hung224f82f2022-03-22 00:00:49 -0700857 TIME_CHECK();
jiabinf6eb4c32020-02-25 14:06:25 -0800858 if (mStream == nullptr) return NO_INIT;
859 mEventCallback = callback;
860 status_t status = processReturn(
861 "setEventCallback",
862 mStream->setEventCallback(
863 callback.get() == nullptr ? nullptr : new StreamOutEventCallback(this)));
864 return status;
865}
866#endif
867
Eric Laurentafa586b2022-01-27 21:10:55 +0100868#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
869using hardware::audio::V7_1::LatencyMode;
870
871status_t StreamOutHalHidl::setLatencyMode(audio_latency_mode_t mode) {
Andy Hung224f82f2022-03-22 00:00:49 -0700872 TIME_CHECK();
Eric Laurentafa586b2022-01-27 21:10:55 +0100873 if (mStream == 0) return NO_INIT;
874 return processReturn(
875 "setLatencyMode", mStream->setLatencyMode(static_cast<LatencyMode>(mode)));
876};
877
878status_t StreamOutHalHidl::getRecommendedLatencyModes(std::vector<audio_latency_mode_t> *modes) {
Andy Hung224f82f2022-03-22 00:00:49 -0700879 TIME_CHECK();
Eric Laurentafa586b2022-01-27 21:10:55 +0100880 if (!mStream) return NO_INIT;
881 Result retval;
882 Return<void> ret = mStream->getRecommendedLatencyModes(
883 [&](Result r, hidl_vec<LatencyMode> hidlModes) {
884 retval = r;
885 for (size_t i = 0; i < hidlModes.size(); i++) {
886 modes->push_back(static_cast<audio_latency_mode_t>(hidlModes[i]));
887 }
888 });
889 return processReturn("getRecommendedLatencyModes", ret, retval);
890};
891
892#include PATH(android/hardware/audio/FILE_VERSION/IStreamOutLatencyModeCallback.h)
893
894using hardware::audio::V7_1::IStreamOutLatencyModeCallback;
895
896namespace {
897struct StreamOutLatencyModeCallback : public IStreamOutLatencyModeCallback {
898 StreamOutLatencyModeCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
899
900 // IStreamOutLatencyModeCallback implementation
901 Return<void> onRecommendedLatencyModeChanged(const hidl_vec<LatencyMode>& hidlModes) override {
902 sp<StreamOutHalHidl> stream = mStream.promote();
903 if (stream != nullptr) {
904 std::vector<audio_latency_mode_t> modes;
905 for (size_t i = 0; i < hidlModes.size(); i++) {
906 modes.push_back(static_cast<audio_latency_mode_t>(hidlModes[i]));
907 }
908 stream->onRecommendedLatencyModeChanged(modes);
909 }
910 return Void();
911 }
912
913 private:
914 wp<StreamOutHalHidl> mStream;
915};
916} // namespace
917
918status_t StreamOutHalHidl::setLatencyModeCallback(
919 const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) {
Andy Hung224f82f2022-03-22 00:00:49 -0700920 TIME_CHECK();
Eric Laurentafa586b2022-01-27 21:10:55 +0100921
922 if (mStream == nullptr) return NO_INIT;
923 mLatencyModeCallback = callback;
924 status_t status = processReturn(
925 "setLatencyModeCallback",
926 mStream->setLatencyModeCallback(
927 callback.get() == nullptr ? nullptr : new StreamOutLatencyModeCallback(this)));
928 return status;
929};
930
931#else
932
933status_t StreamOutHalHidl::setLatencyMode(audio_latency_mode_t mode __unused) {
934 return INVALID_OPERATION;
935};
936
937status_t StreamOutHalHidl::getRecommendedLatencyModes(
938 std::vector<audio_latency_mode_t> *modes __unused) {
939 return INVALID_OPERATION;
940};
941
942status_t StreamOutHalHidl::setLatencyModeCallback(
943 const sp<StreamOutHalInterfaceLatencyModeCallback>& callback __unused) {
944 return INVALID_OPERATION;
945};
946
947#endif
948
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800949void StreamOutHalHidl::onWriteReady() {
Andy Hung638f45b2021-01-18 20:02:56 -0800950 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800951 if (callback == 0) return;
952 ALOGV("asyncCallback onWriteReady");
953 callback->onWriteReady();
954}
955
956void StreamOutHalHidl::onDrainReady() {
Andy Hung638f45b2021-01-18 20:02:56 -0800957 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800958 if (callback == 0) return;
959 ALOGV("asyncCallback onDrainReady");
960 callback->onDrainReady();
961}
962
963void StreamOutHalHidl::onError() {
Andy Hung638f45b2021-01-18 20:02:56 -0800964 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800965 if (callback == 0) return;
966 ALOGV("asyncCallback onError");
967 callback->onError();
968}
969
jiabinf6eb4c32020-02-25 14:06:25 -0800970void StreamOutHalHidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) {
Andy Hung638f45b2021-01-18 20:02:56 -0800971 sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.load().promote();
jiabinf6eb4c32020-02-25 14:06:25 -0800972 if (callback == nullptr) return;
973 ALOGV("asyncCodecFormatCallback %s", __func__);
974 callback->onCodecFormatChanged(metadataBs);
975}
976
Eric Laurentafa586b2022-01-27 21:10:55 +0100977void StreamOutHalHidl::onRecommendedLatencyModeChanged(
978 const std::vector<audio_latency_mode_t>& modes) {
979 sp<StreamOutHalInterfaceLatencyModeCallback> callback = mLatencyModeCallback.load().promote();
980 if (callback == nullptr) return;
981 callback->onRecommendedLatencyModeChanged(modes);
982}
983
Ytai Ben-Tsvi7e0183f2022-02-04 10:49:54 -0800984status_t StreamOutHalHidl::exit() {
Mikhail Naganov0211cd92023-06-14 01:02:39 +0000985 // Signal exiting to HALs that use intermediate pipes to close them.
Andy Hungb72a5502023-03-27 15:53:06 -0700986 AudioParameter param;
987 param.addInt(String8(AudioParameter::keyExiting), 1);
Mikhail Naganov0211cd92023-06-14 01:02:39 +0000988 param.add(String8(AudioParameter::keyClosing), String8(AudioParameter::valueTrue));
Andy Hungb72a5502023-03-27 15:53:06 -0700989 return setParameters(param.toString());
Ytai Ben-Tsvi7e0183f2022-02-04 10:49:54 -0800990}
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800991
Mikhail Naganov6718c392022-01-27 22:17:21 +0000992StreamInHalHidl::StreamInHalHidl(
Mikhail Naganovaccbe8a2022-02-03 23:45:36 +0000993 const sp<::android::hardware::audio::CORE_TYPES_CPP_VERSION::IStreamIn>& stream)
Andy Hung224f82f2022-03-22 00:00:49 -0700994 : StreamHalHidl("StreamInHalHidl", stream.get())
995 , mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800996}
997
998StreamInHalHidl::~StreamInHalHidl() {
999 if (mStream != 0) {
1000 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001001 }
1002 if (mEfGroup) {
1003 EventFlag::deleteEventFlag(&mEfGroup);
1004 }
1005}
1006
1007status_t StreamInHalHidl::getFrameSize(size_t *size) {
Andy Hung224f82f2022-03-22 00:00:49 -07001008 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001009 if (mStream == 0) return NO_INIT;
1010 return processReturn("getFrameSize", mStream->getFrameSize(), size);
1011}
1012
1013status_t StreamInHalHidl::setGain(float gain) {
Andy Hung224f82f2022-03-22 00:00:49 -07001014 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001015 if (mStream == 0) return NO_INIT;
1016 return processReturn("setGain", mStream->setGain(gain));
1017}
1018
1019status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
Shunkai Yaoc6308712023-02-22 17:53:04 +00001020 // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001021 if (mStream == 0) return NO_INIT;
1022 *read = 0;
1023
1024 if (bytes == 0 && !mDataMQ) {
1025 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
1026 return OK;
1027 }
1028
1029 status_t status;
1030 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
1031 return status;
1032 }
1033
1034 ReadParameters params;
1035 params.command = ReadCommand::READ;
1036 params.params.read = bytes;
1037 status = callReaderThread(params, "read",
1038 [&](const ReadStatus& readStatus) {
1039 const size_t availToRead = mDataMQ->availableToRead();
1040 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
1041 ALOGE("data message queue read failed for \"read\"");
1042 }
1043 ALOGW_IF(availToRead != readStatus.reply.read,
1044 "HAL read report inconsistent: mq = %d, status = %d",
1045 (int32_t)availToRead, (int32_t)readStatus.reply.read);
1046 *read = readStatus.reply.read;
1047 });
1048 mStreamPowerLog.log(buffer, *read);
1049 return status;
1050}
1051
1052status_t StreamInHalHidl::callReaderThread(
1053 const ReadParameters& params, const char* cmdName,
1054 StreamInHalHidl::ReaderCallback callback) {
1055 if (!mCommandMQ->write(&params)) {
1056 ALOGW("command message queue write failed");
1057 return -EAGAIN;
1058 }
1059 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
1060
1061 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
1062 uint32_t efState = 0;
1063retry:
1064 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
1065 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
1066 ReadStatus readStatus;
1067 readStatus.retval = Result::NOT_INITIALIZED;
1068 if (!mStatusMQ->read(&readStatus)) {
1069 ALOGE("status message read failed for \"%s\"", cmdName);
1070 }
1071 if (readStatus.retval == Result::OK) {
1072 ret = OK;
1073 callback(readStatus);
1074 } else {
1075 ret = processReturn(cmdName, readStatus.retval);
1076 }
1077 return ret;
1078 }
1079 if (ret == -EAGAIN || ret == -EINTR) {
1080 // Spurious wakeup. This normally retries no more than once.
1081 goto retry;
1082 }
1083 return ret;
1084}
1085
1086status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
1087 std::unique_ptr<CommandMQ> tempCommandMQ;
1088 std::unique_ptr<DataMQ> tempDataMQ;
1089 std::unique_ptr<StatusMQ> tempStatusMQ;
1090 Result retval;
1091 pid_t halThreadPid, halThreadTid;
1092 Return<void> ret = mStream->prepareForReading(
1093 1, bufferSize,
1094 [&](Result r,
1095 const CommandMQ::Descriptor& commandMQ,
1096 const DataMQ::Descriptor& dataMQ,
1097 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001098 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001099 retval = r;
1100 if (retval == Result::OK) {
1101 tempCommandMQ.reset(new CommandMQ(commandMQ));
1102 tempDataMQ.reset(new DataMQ(dataMQ));
1103 tempStatusMQ.reset(new StatusMQ(statusMQ));
1104 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
1105 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
1106 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001107#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001108 halThreadPid = halThreadInfo.pid;
1109 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001110#else
1111 halThreadTid = halThreadInfo;
1112#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001113 }
1114 });
1115 if (!ret.isOk() || retval != Result::OK) {
1116 return processReturn("prepareForReading", ret, retval);
1117 }
1118 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
1119 !tempDataMQ || !tempDataMQ->isValid() ||
1120 !tempStatusMQ || !tempStatusMQ->isValid() ||
1121 !mEfGroup) {
1122 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
1123 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
1124 "Command message queue for writing is invalid");
1125 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
1126 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
1127 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
1128 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
1129 "Status message queue for reading is invalid");
1130 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
1131 return NO_INIT;
1132 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001133#if MAJOR_VERSION >= 7
1134 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
1135 return status;
1136 }
1137#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001138 requestHalThreadPriority(halThreadPid, halThreadTid);
1139
1140 mCommandMQ = std::move(tempCommandMQ);
1141 mDataMQ = std::move(tempDataMQ);
1142 mStatusMQ = std::move(tempStatusMQ);
1143 mReaderClient = gettid();
1144 return OK;
1145}
1146
1147status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
Andy Hung224f82f2022-03-22 00:00:49 -07001148 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001149 if (mStream == 0) return NO_INIT;
1150 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
1151}
1152
1153status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
Shunkai Yaoc6308712023-02-22 17:53:04 +00001154 // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001155 if (mStream == 0) return NO_INIT;
1156 if (mReaderClient == gettid() && mCommandMQ) {
1157 ReadParameters params;
1158 params.command = ReadCommand::GET_CAPTURE_POSITION;
1159 return callReaderThread(params, "getCapturePosition",
1160 [&](const ReadStatus& readStatus) {
1161 *frames = readStatus.reply.capturePosition.frames;
1162 *time = readStatus.reply.capturePosition.time;
1163 });
1164 } else {
1165 Result retval;
1166 Return<void> ret = mStream->getCapturePosition(
1167 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
1168 retval = r;
1169 if (retval == Result::OK) {
1170 *frames = hidlFrames;
1171 *time = hidlTime;
1172 }
1173 });
1174 return processReturn("getCapturePosition", ret, retval);
1175 }
1176}
1177
Kevin Rocard070e7512018-05-22 09:29:13 -07001178#if MAJOR_VERSION == 2
1179status_t StreamInHalHidl::getActiveMicrophones(
Mikhail Naganov2a6a3012023-02-13 11:45:03 -08001180 std::vector<media::MicrophoneInfoFw> *microphones __unused) {
Kevin Rocard070e7512018-05-22 09:29:13 -07001181 if (mStream == 0) return NO_INIT;
1182 return INVALID_OPERATION;
1183}
1184
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001185status_t StreamInHalHidl::updateSinkMetadata(
1186 const StreamInHalInterface::SinkMetadata& /* sinkMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -07001187 // Audio HAL V2.0 does not support propagating sink metadata
1188 return INVALID_OPERATION;
1189}
1190
Kevin Rocard3d48dce2018-11-08 17:16:57 -08001191#elif MAJOR_VERSION >= 4
jiabin9ff780e2018-03-19 18:19:52 -07001192status_t StreamInHalHidl::getActiveMicrophones(
Mikhail Naganov2a6a3012023-02-13 11:45:03 -08001193 std::vector<media::MicrophoneInfoFw> *microphonesInfo) {
Andy Hung224f82f2022-03-22 00:00:49 -07001194 TIME_CHECK();
jiabin9ff780e2018-03-19 18:19:52 -07001195 if (!mStream) return NO_INIT;
1196 Result retval;
1197 Return<void> ret = mStream->getActiveMicrophones(
1198 [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
1199 retval = r;
1200 for (size_t k = 0; k < micArrayHal.size(); k++) {
Mikhail Naganov2a6a3012023-02-13 11:45:03 -08001201 // Convert via legacy.
jiabin9ff780e2018-03-19 18:19:52 -07001202 audio_microphone_characteristic_t dst;
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001203 (void)CoreUtils::microphoneInfoToHal(micArrayHal[k], &dst);
Mikhail Naganov2a6a3012023-02-13 11:45:03 -08001204 auto conv = legacy2aidl_audio_microphone_characteristic_t_MicrophoneInfoFw(dst);
1205 if (conv.ok()) {
1206 microphonesInfo->push_back(conv.value());
1207 } else {
1208 ALOGW("getActiveMicrophones: could not convert %s to AIDL: %d",
1209 toString(micArrayHal[k]).c_str(), conv.error());
1210 microphonesInfo->push_back(media::MicrophoneInfoFw{});
1211 }
jiabin9ff780e2018-03-19 18:19:52 -07001212 }
1213 });
1214 return processReturn("getActiveMicrophones", ret, retval);
1215}
1216
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001217status_t StreamInHalHidl::updateSinkMetadata(const
1218 StreamInHalInterface::SinkMetadata& sinkMetadata) {
Andy Hung224f82f2022-03-22 00:00:49 -07001219 TIME_CHECK();
Mikhail Naganov6718c392022-01-27 22:17:21 +00001220#if MAJOR_VERSION == 4
1221 ::android::hardware::audio::CORE_TYPES_CPP_VERSION::SinkMetadata hidlMetadata;
1222#else
1223 ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::SinkMetadata hidlMetadata;
1224#endif
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001225 if (status_t status = CoreUtils::sinkMetadataFromHalV7(
1226 sinkMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
1227 status != OK) {
1228 return status;
1229 }
1230 return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -07001231}
Kevin Rocard070e7512018-05-22 09:29:13 -07001232#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -07001233
Paul McLean03a6e6a2018-12-04 10:54:13 -07001234#if MAJOR_VERSION < 5
Paul McLean12340082019-03-19 09:35:05 -06001235status_t StreamInHalHidl::setPreferredMicrophoneDirection(
1236 audio_microphone_direction_t direction __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001237 if (mStream == 0) return NO_INIT;
1238 return INVALID_OPERATION;
1239}
1240
Paul McLean12340082019-03-19 09:35:05 -06001241status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001242 if (mStream == 0) return NO_INIT;
1243 return INVALID_OPERATION;
1244}
1245#else
Paul McLean12340082019-03-19 09:35:05 -06001246status_t StreamInHalHidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
Andy Hung224f82f2022-03-22 00:00:49 -07001247 TIME_CHECK();
Paul McLean03a6e6a2018-12-04 10:54:13 -07001248 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001249 return processReturn("setPreferredMicrophoneDirection",
1250 mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction)));
Paul McLean03a6e6a2018-12-04 10:54:13 -07001251}
1252
Paul McLean12340082019-03-19 09:35:05 -06001253status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom) {
Andy Hung224f82f2022-03-22 00:00:49 -07001254 TIME_CHECK();
Paul McLean03a6e6a2018-12-04 10:54:13 -07001255 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001256 return processReturn("setPreferredMicrophoneFieldDimension",
Paul McLean03a6e6a2018-12-04 10:54:13 -07001257 mStream->setMicrophoneFieldDimension(zoom));
1258}
1259#endif
1260
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001261} // namespace android