blob: 9e22700c4c57be8ca8ed2306167b9d2896cd4884 [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 Naganovf450ced2024-05-10 13:30:40 -070020#include <cinttypes>
21
Mikhail Naganov247b5f92021-01-15 19:16:12 +000022#include <android/hidl/manager/1.0/IServiceManager.h>
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080023#include <hwbinder/IPCThreadState.h>
Mikhail Naganovac917ac2018-11-28 14:03:52 -080024#include <media/AudioParameter.h>
Ytai Ben-Tsvidb6f8982022-02-07 12:06:23 -080025#include <mediautils/memory.h>
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080026#include <mediautils/SchedulingPolicyService.h>
Andy Hung224f82f2022-03-22 00:00:49 -070027#include <mediautils/TimeCheck.h>
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080028#include <utils/Log.h>
Mikhail Naganov2a6a3012023-02-13 11:45:03 -080029#if MAJOR_VERSION >= 4
30#include <media/AidlConversion.h>
31#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080032
Mikhail Naganov6718c392022-01-27 22:17:21 +000033#include PATH(android/hardware/audio/CORE_TYPES_FILE_VERSION/IStreamOutCallback.h)
Mikhail Naganov247b5f92021-01-15 19:16:12 +000034#include <HidlUtils.h>
35#include <util/CoreUtils.h>
36
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080037#include "DeviceHalHidl.h"
Mikhail Naganov89c22e42023-06-14 15:49:59 -070038#include "EffectHalHidl.h"
Mikhail Naganov247b5f92021-01-15 19:16:12 +000039#include "ParameterUtils.h"
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080040#include "StreamHalHidl.h"
41
Mikhail Naganov6718c392022-01-27 22:17:21 +000042using ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::implementation::HidlUtils;
43using ::android::hardware::audio::CORE_TYPES_CPP_VERSION::implementation::CoreUtils;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080044using ::android::hardware::MQDescriptorSync;
45using ::android::hardware::Return;
46using ::android::hardware::Void;
Kevin Rocarddf9b4202018-05-10 19:56:08 -070047
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080048namespace android {
49
Mikhail Naganovaccbe8a2022-02-03 23:45:36 +000050using ReadCommand = ::android::hardware::audio::CORE_TYPES_CPP_VERSION::IStreamIn::ReadCommand;
Mikhail Naganov9ccaa162018-12-12 10:27:29 -080051
Mikhail Naganov6718c392022-01-27 22:17:21 +000052using namespace ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION;
53using namespace ::android::hardware::audio::CORE_TYPES_CPP_VERSION;
Mikhail Naganov9ccaa162018-12-12 10:27:29 -080054
Andy Hung224f82f2022-03-22 00:00:49 -070055StreamHalHidl::StreamHalHidl(std::string_view className, IStream *stream)
Mikhail Naganov288a3432022-03-25 00:29:56 +000056 : CoreConversionHelperHidl(className),
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080057 mStream(stream),
58 mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT),
59 mCachedBufferSize(0){
60
61 // Instrument audio signal power logging.
62 // Note: This assumes channel mask, format, and sample rate do not change after creation.
Mikhail Naganov247b5f92021-01-15 19:16:12 +000063 audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
64 if (/* mStreamPowerLog.isUserDebugOrEngBuild() && */
Mikhail Naganov560637e2021-03-31 22:40:13 +000065 StreamHalHidl::getAudioProperties(&config) == NO_ERROR) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +000066 mStreamPowerLog.init(config.sample_rate, config.channel_mask, config.format);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080067 }
68}
69
Andy Hungacb5b982021-01-20 10:12:00 -080070StreamHalHidl::~StreamHalHidl() {
71 // The last step is to flush all binder commands so that the deletion
72 // of IStreamIn / IStreamOut (mStream) is issued with less delay. See b/35394629.
73 hardware::IPCThreadState::self()->flushCommands();
74}
75
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080076status_t StreamHalHidl::getBufferSize(size_t *size) {
Andy Hung224f82f2022-03-22 00:00:49 -070077 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080078 if (!mStream) return NO_INIT;
79 status_t status = processReturn("getBufferSize", mStream->getBufferSize(), size);
80 if (status == OK) {
81 mCachedBufferSize = *size;
82 }
83 return status;
84}
85
Mikhail Naganov560637e2021-03-31 22:40:13 +000086status_t StreamHalHidl::getAudioProperties(audio_config_base_t *configBase) {
Andy Hung224f82f2022-03-22 00:00:49 -070087 TIME_CHECK();
Mikhail Naganov560637e2021-03-31 22:40:13 +000088 *configBase = AUDIO_CONFIG_BASE_INITIALIZER;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080089 if (!mStream) return NO_INIT;
Mikhail Naganov247b5f92021-01-15 19:16:12 +000090#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080091 Return<void> ret = mStream->getAudioProperties(
Kevin Rocardb9cfbf12018-02-23 19:11:06 -080092 [&](uint32_t sr, auto m, auto f) {
Mikhail Naganov560637e2021-03-31 22:40:13 +000093 configBase->sample_rate = sr;
94 configBase->channel_mask = static_cast<audio_channel_mask_t>(m);
95 configBase->format = static_cast<audio_format_t>(f);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080096 });
97 return processReturn("getAudioProperties", ret);
Mikhail Naganov247b5f92021-01-15 19:16:12 +000098#else
99 Result retval;
100 status_t conversionStatus = BAD_VALUE;
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000101 Return<void> ret = mStream->getAudioProperties(
102 [&](Result r, const AudioConfigBase& config) {
103 retval = r;
104 if (retval == Result::OK) {
Mikhail Naganov560637e2021-03-31 22:40:13 +0000105 conversionStatus = HidlUtils::audioConfigBaseToHal(config, configBase);
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000106 }
107 });
108 if (status_t status = processReturn("getAudioProperties", ret, retval); status == NO_ERROR) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000109 return conversionStatus;
110 } else {
111 return status;
112 }
113#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800114}
115
116status_t StreamHalHidl::setParameters(const String8& kvPairs) {
Andy Hung224f82f2022-03-22 00:00:49 -0700117 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800118 if (!mStream) return NO_INIT;
119 hidl_vec<ParameterValue> hidlParams;
120 status_t status = parametersFromHal(kvPairs, &hidlParams);
121 if (status != OK) return status;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800122 return processReturn("setParameters",
Dean Wheatley7b417a22019-01-31 20:39:42 +1100123 utils::setParameters(mStream, {} /* context */, hidlParams));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800124}
125
126status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
Andy Hung224f82f2022-03-22 00:00:49 -0700127 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800128 values->clear();
129 if (!mStream) return NO_INIT;
130 hidl_vec<hidl_string> hidlKeys;
131 status_t status = keysFromHal(keys, &hidlKeys);
132 if (status != OK) return status;
133 Result retval;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800134 Return<void> ret = utils::getParameters(
135 mStream,
136 {} /* context */,
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800137 hidlKeys,
138 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
139 retval = r;
140 if (retval == Result::OK) {
141 parametersToHal(parameters, values);
142 }
143 });
144 return processReturn("getParameters", ret, retval);
145}
146
147status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
Andy Hung224f82f2022-03-22 00:00:49 -0700148 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800149 if (!mStream) return NO_INIT;
Mikhail Naganov89c22e42023-06-14 15:49:59 -0700150 auto hidlEffect = sp<effect::EffectHalHidl>::cast(effect);
151 return processReturn("addEffect", mStream->addEffect(hidlEffect->effectId()));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800152}
153
154status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
Andy Hung224f82f2022-03-22 00:00:49 -0700155 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800156 if (!mStream) return NO_INIT;
Mikhail Naganov89c22e42023-06-14 15:49:59 -0700157 auto hidlEffect = sp<effect::EffectHalHidl>::cast(effect);
158 return processReturn("removeEffect", mStream->removeEffect(hidlEffect->effectId()));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800159}
160
161status_t StreamHalHidl::standby() {
Andy Hung224f82f2022-03-22 00:00:49 -0700162 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800163 if (!mStream) return NO_INIT;
164 return processReturn("standby", mStream->standby());
165}
166
Andy Hung61589a42021-06-16 09:37:53 -0700167status_t StreamHalHidl::dump(int fd, const Vector<String16>& args) {
Andy Hung224f82f2022-03-22 00:00:49 -0700168 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800169 if (!mStream) return NO_INIT;
170 native_handle_t* hidlHandle = native_handle_create(1, 0);
171 hidlHandle->data[0] = fd;
Andy Hung61589a42021-06-16 09:37:53 -0700172 hidl_vec<hidl_string> hidlArgs;
173 argsFromHal(args, &hidlArgs);
174 Return<void> ret = mStream->debug(hidlHandle, hidlArgs);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800175 native_handle_delete(hidlHandle);
Andy Hunge72ff022021-08-16 10:16:15 -0700176
177 // TODO(b/111997867, b/177271958) Workaround - remove when fixed.
178 // A Binder transmitted fd may not close immediately due to a race condition b/111997867
179 // when the remote binder thread removes the last refcount to the fd blocks in the
180 // kernel for binder activity. We send a Binder ping() command to unblock the thread
181 // and complete the fd close / release.
182 //
183 // See DeviceHalHidl::dump(), EffectHalHidl::dump(), StreamHalHidl::dump(),
184 // EffectsFactoryHalHidl::dumpEffects().
185
186 (void)mStream->ping(); // synchronous Binder call
187
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800188 mStreamPowerLog.dump(fd);
189 return processReturn("dump", ret);
190}
191
192status_t StreamHalHidl::start() {
Andy Hung224f82f2022-03-22 00:00:49 -0700193 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800194 if (!mStream) return NO_INIT;
195 return processReturn("start", mStream->start());
196}
197
198status_t StreamHalHidl::stop() {
Andy Hung224f82f2022-03-22 00:00:49 -0700199 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800200 if (!mStream) return NO_INIT;
201 return processReturn("stop", mStream->stop());
202}
203
204status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
205 struct audio_mmap_buffer_info *info) {
Andy Hung224f82f2022-03-22 00:00:49 -0700206 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800207 Result retval;
208 Return<void> ret = mStream->createMmapBuffer(
209 minSizeFrames,
210 [&](Result r, const MmapBufferInfo& hidlInfo) {
211 retval = r;
212 if (retval == Result::OK) {
213 const native_handle *handle = hidlInfo.sharedMemory.handle();
214 if (handle->numFds > 0) {
215 info->shared_memory_fd = handle->data[0];
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800216#if MAJOR_VERSION >= 4
Kevin Rocard734334f2018-07-12 19:37:41 -0700217 info->flags = audio_mmap_buffer_flag(hidlInfo.flags);
218#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800219 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
Kevin Rocard734334f2018-07-12 19:37:41 -0700220 // Negative buffer size frame was a hack in O and P to
221 // indicate that the buffer is shareable to applications
222 if (info->buffer_size_frames < 0) {
223 info->buffer_size_frames *= -1;
224 info->flags = audio_mmap_buffer_flag(
225 info->flags | AUDIO_MMAP_APPLICATION_SHAREABLE);
226 }
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800227 info->burst_size_frames = hidlInfo.burstSizeFrames;
228 // info->shared_memory_address is not needed in HIDL context
229 info->shared_memory_address = NULL;
230 } else {
231 retval = Result::NOT_INITIALIZED;
232 }
233 }
234 });
235 return processReturn("createMmapBuffer", ret, retval);
236}
237
238status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
Andy Hung224f82f2022-03-22 00:00:49 -0700239 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800240 Result retval;
241 Return<void> ret = mStream->getMmapPosition(
242 [&](Result r, const MmapPosition& hidlPosition) {
243 retval = r;
244 if (retval == Result::OK) {
245 position->time_nanoseconds = hidlPosition.timeNanoseconds;
246 position->position_frames = hidlPosition.positionFrames;
247 }
248 });
249 return processReturn("getMmapPosition", ret, retval);
250}
251
252status_t StreamHalHidl::setHalThreadPriority(int priority) {
253 mHalThreadPriority = priority;
254 return OK;
255}
256
257status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
258 if (mCachedBufferSize != 0) {
259 *size = mCachedBufferSize;
260 return OK;
261 }
262 return getBufferSize(size);
263}
264
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000265status_t StreamHalHidl::getHalPid(pid_t *pid) {
266 using ::android::hidl::base::V1_0::DebugInfo;
267 using ::android::hidl::manager::V1_0::IServiceManager;
Andy Hung224f82f2022-03-22 00:00:49 -0700268 TIME_CHECK();
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000269 DebugInfo debugInfo;
270 auto ret = mStream->getDebugInfo([&] (const auto &info) {
271 debugInfo = info;
272 });
273 if (!ret.isOk()) {
274 return INVALID_OPERATION;
275 }
276 if (debugInfo.pid != (int)IServiceManager::PidConstant::NO_PID) {
277 *pid = debugInfo.pid;
278 return NO_ERROR;
279 }
280 return NAME_NOT_FOUND;
281}
282
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800283bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
284 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
285 return true;
286 }
287 int err = requestPriority(
288 threadPid, threadId,
289 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
290 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
291 mHalThreadPriority, threadPid, threadId, err);
292 // Audio will still work, but latency will be higher and sometimes unacceptable.
293 return err == 0;
294}
295
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800296status_t StreamHalHidl::legacyCreateAudioPatch(const struct audio_port_config& port,
297 std::optional<audio_source_t> source,
298 audio_devices_t type) {
Andy Hung224f82f2022-03-22 00:00:49 -0700299 TIME_CHECK();
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800300 LOG_ALWAYS_FATAL_IF(port.type != AUDIO_PORT_TYPE_DEVICE, "port type must be device");
Ytai Ben-Tsvidb6f8982022-02-07 12:06:23 -0800301 unique_malloced_ptr<char> address;
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800302 if (strcmp(port.ext.device.address, "") != 0) {
303 // FIXME: we only support address on first sink with HAL version < 3.0
Ytai Ben-Tsvidb6f8982022-02-07 12:06:23 -0800304 address.reset(
305 audio_device_address_to_parameter(port.ext.device.type, port.ext.device.address));
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800306 } else {
Ytai Ben-Tsvidb6f8982022-02-07 12:06:23 -0800307 address.reset((char*)calloc(1, 1));
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800308 }
Ytai Ben-Tsvidb6f8982022-02-07 12:06:23 -0800309 AudioParameter param = AudioParameter(String8(address.get()));
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800310 param.addInt(String8(AudioParameter::keyRouting), (int)type);
311 if (source.has_value()) {
312 param.addInt(String8(AudioParameter::keyInputSource), (int)source.value());
313 }
314 return setParameters(param.toString());
315}
316
317status_t StreamHalHidl::legacyReleaseAudioPatch() {
Andy Hung224f82f2022-03-22 00:00:49 -0700318 TIME_CHECK();
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800319 AudioParameter param;
320 param.addInt(String8(AudioParameter::keyRouting), 0);
321 return setParameters(param.toString());
322}
323
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800324namespace {
325
326/* Notes on callback ownership.
327
328This is how (Hw)Binder ownership model looks like. The server implementation
329is owned by Binder framework (via sp<>). Proxies are owned by clients.
330When the last proxy disappears, Binder framework releases the server impl.
331
332Thus, it is not needed to keep any references to StreamOutCallback (this is
333the server impl) -- it will live as long as HAL server holds a strong ref to
334IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
335from the destructor of StreamOutHalHidl.
336
337The callback only keeps a weak reference to the stream. The stream is owned
338by AudioFlinger.
339
340*/
341
342struct StreamOutCallback : public IStreamOutCallback {
343 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
344
345 // IStreamOutCallback implementation
346 Return<void> onWriteReady() override {
347 sp<StreamOutHalHidl> stream = mStream.promote();
348 if (stream != 0) {
349 stream->onWriteReady();
350 }
351 return Void();
352 }
353
354 Return<void> onDrainReady() override {
355 sp<StreamOutHalHidl> stream = mStream.promote();
356 if (stream != 0) {
357 stream->onDrainReady();
358 }
359 return Void();
360 }
361
362 Return<void> onError() override {
363 sp<StreamOutHalHidl> stream = mStream.promote();
364 if (stream != 0) {
365 stream->onError();
366 }
367 return Void();
368 }
369
370 private:
Andy Hung638f45b2021-01-18 20:02:56 -0800371 const wp<StreamOutHalHidl> mStream;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800372};
373
374} // namespace
375
Mikhail Naganov6718c392022-01-27 22:17:21 +0000376StreamOutHalHidl::StreamOutHalHidl(
377 const sp<::android::hardware::audio::CPP_VERSION::IStreamOut>& stream)
Andy Hung224f82f2022-03-22 00:00:49 -0700378 : StreamHalHidl("StreamOutHalHidl", stream.get())
379 , mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800380}
381
382StreamOutHalHidl::~StreamOutHalHidl() {
383 if (mStream != 0) {
Andy Hung638f45b2021-01-18 20:02:56 -0800384 if (mCallback.load().unsafe_get()) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800385 processReturn("clearCallback", mStream->clearCallback());
386 }
jiabinf6eb4c32020-02-25 14:06:25 -0800387#if MAJOR_VERSION >= 6
Andy Hung638f45b2021-01-18 20:02:56 -0800388 if (mEventCallback.load().unsafe_get() != nullptr) {
jiabinf6eb4c32020-02-25 14:06:25 -0800389 processReturn("setEventCallback",
390 mStream->setEventCallback(nullptr));
391 }
392#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800393 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800394 }
Andy Hung638f45b2021-01-18 20:02:56 -0800395 mCallback = nullptr;
396 mEventCallback = nullptr;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800397 if (mEfGroup) {
398 EventFlag::deleteEventFlag(&mEfGroup);
399 }
400}
401
402status_t StreamOutHalHidl::getFrameSize(size_t *size) {
Andy Hung224f82f2022-03-22 00:00:49 -0700403 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800404 if (mStream == 0) return NO_INIT;
405 return processReturn("getFrameSize", mStream->getFrameSize(), size);
406}
407
408status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
Andy Hung224f82f2022-03-22 00:00:49 -0700409 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800410 if (mStream == 0) return NO_INIT;
411 if (mWriterClient == gettid() && mCommandMQ) {
412 return callWriterThread(
413 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
414 [&](const WriteStatus& writeStatus) {
415 *latency = writeStatus.reply.latencyMs;
416 });
417 } else {
418 return processReturn("getLatency", mStream->getLatency(), latency);
419 }
420}
421
422status_t StreamOutHalHidl::setVolume(float left, float right) {
Andy Hung224f82f2022-03-22 00:00:49 -0700423 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800424 if (mStream == 0) return NO_INIT;
425 return processReturn("setVolume", mStream->setVolume(left, right));
426}
427
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800428#if MAJOR_VERSION == 2
429status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
Andy Hung224f82f2022-03-22 00:00:49 -0700430 TIME_CHECK();
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800431 if (mStream == 0) return NO_INIT;
432 std::vector<ParameterValue> parameters;
433 String8 halParameters;
434 parameters.push_back({AudioParameter::keyPresentationId, std::to_string(presentationId)});
435 parameters.push_back({AudioParameter::keyProgramId, std::to_string(programId)});
436 parametersToHal(hidl_vec<ParameterValue>(parameters), &halParameters);
437 return setParameters(halParameters);
438}
Kevin Rocard1cf6b4d2018-11-20 18:05:44 -0800439#elif MAJOR_VERSION >= 4
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800440status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
Andy Hung224f82f2022-03-22 00:00:49 -0700441 TIME_CHECK();
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800442 if (mStream == 0) return NO_INIT;
443 return processReturn("selectPresentation",
444 mStream->selectPresentation(presentationId, programId));
445}
446#endif
447
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800448status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
Shunkai Yaoc6308712023-02-22 17:53:04 +0000449 // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800450 if (mStream == 0) return NO_INIT;
451 *written = 0;
452
453 if (bytes == 0 && !mDataMQ) {
454 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
Andy Hung638f45b2021-01-18 20:02:56 -0800455 ALOGW_IF(mCallback.load().unsafe_get(), "First call to async write with 0 bytes");
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800456 return OK;
457 }
458
459 status_t status;
460 if (!mDataMQ) {
461 // In case if playback starts close to the end of a compressed track, the bytes
462 // that need to be written is less than the actual buffer size. Need to use
463 // full buffer size for the MQ since otherwise after seeking back to the middle
464 // data will be truncated.
465 size_t bufferSize;
466 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
467 return status;
468 }
469 if (bytes > bufferSize) bufferSize = bytes;
470 if ((status = prepareForWriting(bufferSize)) != OK) {
471 return status;
472 }
473 }
474
475 status = callWriterThread(
476 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
477 [&] (const WriteStatus& writeStatus) {
478 *written = writeStatus.reply.written;
479 // Diagnostics of the cause of b/35813113.
480 ALOGE_IF(*written > bytes,
481 "hal reports more bytes written than asked for: %lld > %lld",
482 (long long)*written, (long long)bytes);
483 });
484 mStreamPowerLog.log(buffer, *written);
485 return status;
486}
487
488status_t StreamOutHalHidl::callWriterThread(
489 WriteCommand cmd, const char* cmdName,
490 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
491 if (!mCommandMQ->write(&cmd)) {
492 ALOGE("command message queue write failed for \"%s\"", cmdName);
493 return -EAGAIN;
494 }
495 if (data != nullptr) {
496 size_t availableToWrite = mDataMQ->availableToWrite();
497 if (dataSize > availableToWrite) {
498 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
499 (long long)dataSize, (long long)availableToWrite);
500 dataSize = availableToWrite;
501 }
502 if (!mDataMQ->write(data, dataSize)) {
503 ALOGE("data message queue write failed for \"%s\"", cmdName);
504 }
505 }
506 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
507
508 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
509 uint32_t efState = 0;
510retry:
511 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
512 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
513 WriteStatus writeStatus;
514 writeStatus.retval = Result::NOT_INITIALIZED;
515 if (!mStatusMQ->read(&writeStatus)) {
516 ALOGE("status message read failed for \"%s\"", cmdName);
517 }
518 if (writeStatus.retval == Result::OK) {
519 ret = OK;
520 callback(writeStatus);
521 } else {
522 ret = processReturn(cmdName, writeStatus.retval);
523 }
524 return ret;
525 }
526 if (ret == -EAGAIN || ret == -EINTR) {
527 // Spurious wakeup. This normally retries no more than once.
528 goto retry;
529 }
530 return ret;
531}
532
533status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
534 std::unique_ptr<CommandMQ> tempCommandMQ;
535 std::unique_ptr<DataMQ> tempDataMQ;
536 std::unique_ptr<StatusMQ> tempStatusMQ;
537 Result retval;
538 pid_t halThreadPid, halThreadTid;
539 Return<void> ret = mStream->prepareForWriting(
540 1, bufferSize,
541 [&](Result r,
542 const CommandMQ::Descriptor& commandMQ,
543 const DataMQ::Descriptor& dataMQ,
544 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000545 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800546 retval = r;
547 if (retval == Result::OK) {
548 tempCommandMQ.reset(new CommandMQ(commandMQ));
549 tempDataMQ.reset(new DataMQ(dataMQ));
550 tempStatusMQ.reset(new StatusMQ(statusMQ));
551 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
552 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
553 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000554#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800555 halThreadPid = halThreadInfo.pid;
556 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000557#else
558 halThreadTid = halThreadInfo;
559#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800560 }
561 });
562 if (!ret.isOk() || retval != Result::OK) {
563 return processReturn("prepareForWriting", ret, retval);
564 }
565 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
566 !tempDataMQ || !tempDataMQ->isValid() ||
567 !tempStatusMQ || !tempStatusMQ->isValid() ||
568 !mEfGroup) {
569 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
570 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
571 "Command message queue for writing is invalid");
572 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
573 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
574 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
575 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
576 "Status message queue for writing is invalid");
577 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
578 return NO_INIT;
579 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000580#if MAJOR_VERSION >= 7
581 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
582 return status;
583 }
584#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800585 requestHalThreadPriority(halThreadPid, halThreadTid);
586
587 mCommandMQ = std::move(tempCommandMQ);
588 mDataMQ = std::move(tempDataMQ);
589 mStatusMQ = std::move(tempStatusMQ);
590 mWriterClient = gettid();
591 return OK;
592}
593
Mikhail Naganovf450ced2024-05-10 13:30:40 -0700594status_t StreamOutHalHidl::getRenderPosition(uint64_t *dspFrames) {
Shunkai Yaoc6308712023-02-22 17:53:04 +0000595 // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800596 if (mStream == 0) return NO_INIT;
597 Result retval;
Mikhail Naganovf450ced2024-05-10 13:30:40 -0700598 uint32_t halPosition = 0;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800599 Return<void> ret = mStream->getRenderPosition(
600 [&](Result r, uint32_t d) {
601 retval = r;
602 if (retval == Result::OK) {
Mikhail Naganovf450ced2024-05-10 13:30:40 -0700603 halPosition = d;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800604 }
605 });
Mikhail Naganovf450ced2024-05-10 13:30:40 -0700606 status_t status = processReturn("getRenderPosition", ret, retval);
607 if (status != OK) {
608 return status;
609 }
610 // Maintain a 64-bit render position using the 32-bit result from the HAL.
611 // This delta calculation relies on the arithmetic overflow behavior
612 // of integers. For example (100 - 0xFFFFFFF0) = 116.
613 std::lock_guard l(mPositionMutex);
614 const auto truncatedPosition = (uint32_t)mRenderPosition;
615 int32_t deltaHalPosition; // initialization not needed, overwitten by __builtin_sub_overflow()
616 (void) __builtin_sub_overflow(halPosition, truncatedPosition, &deltaHalPosition);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800617
Mikhail Naganovf450ced2024-05-10 13:30:40 -0700618 if (deltaHalPosition >= 0) {
619 mRenderPosition += deltaHalPosition;
620 } else if (mExpectRetrograde) {
621 mExpectRetrograde = false;
622 mRenderPosition -= static_cast<uint64_t>(-deltaHalPosition);
623 ALOGW("Retrograde motion of %" PRId32 " frames", -deltaHalPosition);
624 }
625 *dspFrames = mRenderPosition;
626 return OK;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800627}
628
629status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
Andy Hung224f82f2022-03-22 00:00:49 -0700630 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800631 if (mStream == 0) return NO_INIT;
632 status_t status = processReturn(
633 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
634 if (status == OK) {
635 mCallback = callback;
636 }
637 return status;
638}
639
640status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
Andy Hung224f82f2022-03-22 00:00:49 -0700641 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800642 if (mStream == 0) return NO_INIT;
643 Return<void> ret = mStream->supportsPauseAndResume(
644 [&](bool p, bool r) {
645 *supportsPause = p;
646 *supportsResume = r;
647 });
648 return processReturn("supportsPauseAndResume", ret);
649}
650
651status_t StreamOutHalHidl::pause() {
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("pause", mStream->pause());
655}
656
657status_t StreamOutHalHidl::resume() {
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("pause", mStream->resume());
661}
662
663status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
Andy Hung224f82f2022-03-22 00:00:49 -0700664 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800665 if (mStream == 0) return NO_INIT;
666 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
667}
668
669status_t StreamOutHalHidl::drain(bool earlyNotify) {
Andy Hung224f82f2022-03-22 00:00:49 -0700670 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800671 if (mStream == 0) return NO_INIT;
672 return processReturn(
673 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
674}
675
676status_t StreamOutHalHidl::flush() {
Andy Hung224f82f2022-03-22 00:00:49 -0700677 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800678 if (mStream == 0) return NO_INIT;
Mikhail Naganovf450ced2024-05-10 13:30:40 -0700679 {
680 std::lock_guard l(mPositionMutex);
681 mRenderPosition = 0;
682 mExpectRetrograde = false;
683 }
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800684 return processReturn("pause", mStream->flush());
685}
686
Mikhail Naganovf450ced2024-05-10 13:30:40 -0700687status_t StreamOutHalHidl::standby() {
688 {
689 std::lock_guard l(mPositionMutex);
690 mRenderPosition = 0;
691 mExpectRetrograde = false;
692 }
693 return StreamHalHidl::standby();
694}
695
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800696status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
Shunkai Yaoc6308712023-02-22 17:53:04 +0000697 // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800698 if (mStream == 0) return NO_INIT;
699 if (mWriterClient == gettid() && mCommandMQ) {
700 return callWriterThread(
701 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
702 [&](const WriteStatus& writeStatus) {
703 *frames = writeStatus.reply.presentationPosition.frames;
704 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
705 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
706 });
707 } else {
708 Result retval;
709 Return<void> ret = mStream->getPresentationPosition(
710 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
711 retval = r;
712 if (retval == Result::OK) {
713 *frames = hidlFrames;
714 timestamp->tv_sec = hidlTimeStamp.tvSec;
715 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
716 }
717 });
718 return processReturn("getPresentationPosition", ret, retval);
719 }
720}
721
Mikhail Naganovf450ced2024-05-10 13:30:40 -0700722status_t StreamOutHalHidl::presentationComplete() {
723 // Avoid suppressing retrograde motion in mRenderPosition for gapless offload/direct when
724 // transitioning between tracks.
725 // The HAL resets the frame position without flush/stop being called, but calls back prior to
726 // this event. So, on the next occurrence of retrograde motion, we permit backwards movement of
727 // mRenderPosition.
728 mExpectRetrograde = true;
729 return OK;
730}
731
Kevin Rocard070e7512018-05-22 09:29:13 -0700732#if MAJOR_VERSION == 2
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800733status_t StreamOutHalHidl::updateSourceMetadata(
734 const StreamOutHalInterface::SourceMetadata& /* sourceMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700735 // Audio HAL V2.0 does not support propagating source metadata
736 return INVALID_OPERATION;
737}
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800738#elif MAJOR_VERSION >= 4
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800739status_t StreamOutHalHidl::updateSourceMetadata(
740 const StreamOutHalInterface::SourceMetadata& sourceMetadata) {
Andy Hung224f82f2022-03-22 00:00:49 -0700741 TIME_CHECK();
Mikhail Naganov6718c392022-01-27 22:17:21 +0000742#if MAJOR_VERSION == 4
743 ::android::hardware::audio::CORE_TYPES_CPP_VERSION::SourceMetadata hidlMetadata;
744#else
745 ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::SourceMetadata hidlMetadata;
746#endif
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000747 if (status_t status = CoreUtils::sourceMetadataFromHalV7(
748 sourceMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
749 status != OK) {
750 return status;
751 }
752 return processReturn("updateSourceMetadata", mStream->updateSourceMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -0700753}
Kevin Rocard070e7512018-05-22 09:29:13 -0700754#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700755
jiabinf6eb4c32020-02-25 14:06:25 -0800756#if MAJOR_VERSION < 6
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800757status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode __unused) {
758 return INVALID_OPERATION;
759}
760
761status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode __unused) {
762 return INVALID_OPERATION;
763}
764
765status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB __unused) {
766 return INVALID_OPERATION;
767}
768
769status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB __unused) {
770 return INVALID_OPERATION;
771}
772
773status_t StreamOutHalHidl::getPlaybackRateParameters(
774 audio_playback_rate_t* playbackRate __unused) {
775 return INVALID_OPERATION;
776}
777
778status_t StreamOutHalHidl::setPlaybackRateParameters(
779 const audio_playback_rate_t& playbackRate __unused) {
780 return INVALID_OPERATION;
781}
782
jiabinf6eb4c32020-02-25 14:06:25 -0800783status_t StreamOutHalHidl::setEventCallback(
784 const sp<StreamOutHalInterfaceEventCallback>& callback __unused) {
785 // Codec format callback is supported starting from audio HAL V6.0
786 return INVALID_OPERATION;
787}
Eric Laurentafa586b2022-01-27 21:10:55 +0100788
jiabinf6eb4c32020-02-25 14:06:25 -0800789#else
790
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800791status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode) {
Andy Hung224f82f2022-03-22 00:00:49 -0700792 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800793 if (mStream == 0) return NO_INIT;
794 Result retval;
795 Return<void> ret = mStream->getDualMonoMode(
796 [&](Result r, DualMonoMode hidlMode) {
797 retval = r;
798 if (retval == Result::OK) {
799 *mode = static_cast<audio_dual_mono_mode_t>(hidlMode);
800 }
801 });
802 return processReturn("getDualMonoMode", ret, retval);
803}
804
805status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode) {
Andy Hung224f82f2022-03-22 00:00:49 -0700806 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800807 if (mStream == 0) return NO_INIT;
808 return processReturn(
809 "setDualMonoMode", mStream->setDualMonoMode(static_cast<DualMonoMode>(mode)));
810}
811
812status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB) {
Andy Hung224f82f2022-03-22 00:00:49 -0700813 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800814 if (mStream == 0) return NO_INIT;
815 Result retval;
816 Return<void> ret = mStream->getAudioDescriptionMixLevel(
817 [&](Result r, float hidlLeveldB) {
818 retval = r;
819 if (retval == Result::OK) {
820 *leveldB = hidlLeveldB;
821 }
822 });
823 return processReturn("getAudioDescriptionMixLevel", ret, retval);
824}
825
826status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB) {
Andy Hung224f82f2022-03-22 00:00:49 -0700827 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800828 if (mStream == 0) return NO_INIT;
829 return processReturn(
830 "setAudioDescriptionMixLevel", mStream->setAudioDescriptionMixLevel(leveldB));
831}
832
833status_t StreamOutHalHidl::getPlaybackRateParameters(audio_playback_rate_t* playbackRate) {
Andy Hung224f82f2022-03-22 00:00:49 -0700834 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800835 if (mStream == 0) return NO_INIT;
836 Result retval;
837 Return<void> ret = mStream->getPlaybackRateParameters(
838 [&](Result r, PlaybackRate hidlPlaybackRate) {
839 retval = r;
840 if (retval == Result::OK) {
841 playbackRate->mSpeed = hidlPlaybackRate.speed;
842 playbackRate->mPitch = hidlPlaybackRate.pitch;
843 playbackRate->mStretchMode =
844 static_cast<audio_timestretch_stretch_mode_t>(
845 hidlPlaybackRate.timestretchMode);
846 playbackRate->mFallbackMode =
847 static_cast<audio_timestretch_fallback_mode_t>(
848 hidlPlaybackRate.fallbackMode);
849 }
850 });
851 return processReturn("getPlaybackRateParameters", ret, retval);
852}
853
854status_t StreamOutHalHidl::setPlaybackRateParameters(const audio_playback_rate_t& playbackRate) {
Andy Hung224f82f2022-03-22 00:00:49 -0700855 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800856 if (mStream == 0) return NO_INIT;
857 return processReturn(
858 "setPlaybackRateParameters", mStream->setPlaybackRateParameters(
859 PlaybackRate{playbackRate.mSpeed, playbackRate.mPitch,
860 static_cast<TimestretchMode>(playbackRate.mStretchMode),
861 static_cast<TimestretchFallbackMode>(playbackRate.mFallbackMode)}));
862}
863
Mikhail Naganov6718c392022-01-27 22:17:21 +0000864#include PATH(android/hardware/audio/CORE_TYPES_FILE_VERSION/IStreamOutEventCallback.h)
jiabinf6eb4c32020-02-25 14:06:25 -0800865
866namespace {
867
868struct StreamOutEventCallback : public IStreamOutEventCallback {
869 StreamOutEventCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
870
871 // IStreamOutEventCallback implementation
872 Return<void> onCodecFormatChanged(
873 const android::hardware::hidl_vec<uint8_t>& audioMetadata) override {
874 sp<StreamOutHalHidl> stream = mStream.promote();
875 if (stream != nullptr) {
Ryan Prichard78c5e452024-02-08 16:16:57 -0800876 std::vector<uint8_t> metadataBs(audioMetadata.begin(), audioMetadata.end());
jiabinf6eb4c32020-02-25 14:06:25 -0800877 stream->onCodecFormatChanged(metadataBs);
878 }
879 return Void();
880 }
881
882 private:
883 wp<StreamOutHalHidl> mStream;
884};
885
886} // namespace
887
888status_t StreamOutHalHidl::setEventCallback(
889 const sp<StreamOutHalInterfaceEventCallback>& callback) {
Andy Hung224f82f2022-03-22 00:00:49 -0700890 TIME_CHECK();
jiabinf6eb4c32020-02-25 14:06:25 -0800891 if (mStream == nullptr) return NO_INIT;
892 mEventCallback = callback;
893 status_t status = processReturn(
894 "setEventCallback",
895 mStream->setEventCallback(
896 callback.get() == nullptr ? nullptr : new StreamOutEventCallback(this)));
897 return status;
898}
899#endif
900
Eric Laurentafa586b2022-01-27 21:10:55 +0100901#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
902using hardware::audio::V7_1::LatencyMode;
903
904status_t StreamOutHalHidl::setLatencyMode(audio_latency_mode_t mode) {
Andy Hung224f82f2022-03-22 00:00:49 -0700905 TIME_CHECK();
Eric Laurentafa586b2022-01-27 21:10:55 +0100906 if (mStream == 0) return NO_INIT;
907 return processReturn(
908 "setLatencyMode", mStream->setLatencyMode(static_cast<LatencyMode>(mode)));
909};
910
911status_t StreamOutHalHidl::getRecommendedLatencyModes(std::vector<audio_latency_mode_t> *modes) {
Andy Hung224f82f2022-03-22 00:00:49 -0700912 TIME_CHECK();
Eric Laurentafa586b2022-01-27 21:10:55 +0100913 if (!mStream) return NO_INIT;
914 Result retval;
915 Return<void> ret = mStream->getRecommendedLatencyModes(
916 [&](Result r, hidl_vec<LatencyMode> hidlModes) {
917 retval = r;
918 for (size_t i = 0; i < hidlModes.size(); i++) {
919 modes->push_back(static_cast<audio_latency_mode_t>(hidlModes[i]));
920 }
921 });
922 return processReturn("getRecommendedLatencyModes", ret, retval);
923};
924
925#include PATH(android/hardware/audio/FILE_VERSION/IStreamOutLatencyModeCallback.h)
926
927using hardware::audio::V7_1::IStreamOutLatencyModeCallback;
928
929namespace {
930struct StreamOutLatencyModeCallback : public IStreamOutLatencyModeCallback {
931 StreamOutLatencyModeCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
932
933 // IStreamOutLatencyModeCallback implementation
934 Return<void> onRecommendedLatencyModeChanged(const hidl_vec<LatencyMode>& hidlModes) override {
935 sp<StreamOutHalHidl> stream = mStream.promote();
936 if (stream != nullptr) {
937 std::vector<audio_latency_mode_t> modes;
938 for (size_t i = 0; i < hidlModes.size(); i++) {
939 modes.push_back(static_cast<audio_latency_mode_t>(hidlModes[i]));
940 }
941 stream->onRecommendedLatencyModeChanged(modes);
942 }
943 return Void();
944 }
945
946 private:
947 wp<StreamOutHalHidl> mStream;
948};
949} // namespace
950
951status_t StreamOutHalHidl::setLatencyModeCallback(
952 const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) {
Andy Hung224f82f2022-03-22 00:00:49 -0700953 TIME_CHECK();
Eric Laurentafa586b2022-01-27 21:10:55 +0100954
955 if (mStream == nullptr) return NO_INIT;
956 mLatencyModeCallback = callback;
957 status_t status = processReturn(
958 "setLatencyModeCallback",
959 mStream->setLatencyModeCallback(
960 callback.get() == nullptr ? nullptr : new StreamOutLatencyModeCallback(this)));
961 return status;
962};
963
964#else
965
966status_t StreamOutHalHidl::setLatencyMode(audio_latency_mode_t mode __unused) {
967 return INVALID_OPERATION;
968};
969
970status_t StreamOutHalHidl::getRecommendedLatencyModes(
971 std::vector<audio_latency_mode_t> *modes __unused) {
972 return INVALID_OPERATION;
973};
974
975status_t StreamOutHalHidl::setLatencyModeCallback(
976 const sp<StreamOutHalInterfaceLatencyModeCallback>& callback __unused) {
977 return INVALID_OPERATION;
978};
979
980#endif
981
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800982void StreamOutHalHidl::onWriteReady() {
Andy Hung638f45b2021-01-18 20:02:56 -0800983 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800984 if (callback == 0) return;
985 ALOGV("asyncCallback onWriteReady");
986 callback->onWriteReady();
987}
988
989void StreamOutHalHidl::onDrainReady() {
Andy Hung638f45b2021-01-18 20:02:56 -0800990 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800991 if (callback == 0) return;
992 ALOGV("asyncCallback onDrainReady");
993 callback->onDrainReady();
994}
995
996void StreamOutHalHidl::onError() {
Andy Hung638f45b2021-01-18 20:02:56 -0800997 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800998 if (callback == 0) return;
999 ALOGV("asyncCallback onError");
1000 callback->onError();
1001}
1002
Ryan Prichard78c5e452024-02-08 16:16:57 -08001003void StreamOutHalHidl::onCodecFormatChanged(const std::vector<uint8_t>& metadataBs) {
Andy Hung638f45b2021-01-18 20:02:56 -08001004 sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.load().promote();
jiabinf6eb4c32020-02-25 14:06:25 -08001005 if (callback == nullptr) return;
1006 ALOGV("asyncCodecFormatCallback %s", __func__);
1007 callback->onCodecFormatChanged(metadataBs);
1008}
1009
Eric Laurentafa586b2022-01-27 21:10:55 +01001010void StreamOutHalHidl::onRecommendedLatencyModeChanged(
1011 const std::vector<audio_latency_mode_t>& modes) {
1012 sp<StreamOutHalInterfaceLatencyModeCallback> callback = mLatencyModeCallback.load().promote();
1013 if (callback == nullptr) return;
1014 callback->onRecommendedLatencyModeChanged(modes);
1015}
1016
Ytai Ben-Tsvi7e0183f2022-02-04 10:49:54 -08001017status_t StreamOutHalHidl::exit() {
Mikhail Naganov0211cd92023-06-14 01:02:39 +00001018 // Signal exiting to HALs that use intermediate pipes to close them.
Andy Hungb72a5502023-03-27 15:53:06 -07001019 AudioParameter param;
1020 param.addInt(String8(AudioParameter::keyExiting), 1);
Mikhail Naganov0211cd92023-06-14 01:02:39 +00001021 param.add(String8(AudioParameter::keyClosing), String8(AudioParameter::valueTrue));
Andy Hungb72a5502023-03-27 15:53:06 -07001022 return setParameters(param.toString());
Ytai Ben-Tsvi7e0183f2022-02-04 10:49:54 -08001023}
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001024
Mikhail Naganov6718c392022-01-27 22:17:21 +00001025StreamInHalHidl::StreamInHalHidl(
Mikhail Naganovaccbe8a2022-02-03 23:45:36 +00001026 const sp<::android::hardware::audio::CORE_TYPES_CPP_VERSION::IStreamIn>& stream)
Andy Hung224f82f2022-03-22 00:00:49 -07001027 : StreamHalHidl("StreamInHalHidl", stream.get())
1028 , mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001029}
1030
1031StreamInHalHidl::~StreamInHalHidl() {
1032 if (mStream != 0) {
1033 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001034 }
1035 if (mEfGroup) {
1036 EventFlag::deleteEventFlag(&mEfGroup);
1037 }
1038}
1039
1040status_t StreamInHalHidl::getFrameSize(size_t *size) {
Andy Hung224f82f2022-03-22 00:00:49 -07001041 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001042 if (mStream == 0) return NO_INIT;
1043 return processReturn("getFrameSize", mStream->getFrameSize(), size);
1044}
1045
1046status_t StreamInHalHidl::setGain(float gain) {
Andy Hung224f82f2022-03-22 00:00:49 -07001047 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001048 if (mStream == 0) return NO_INIT;
1049 return processReturn("setGain", mStream->setGain(gain));
1050}
1051
1052status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
Shunkai Yaoc6308712023-02-22 17:53:04 +00001053 // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001054 if (mStream == 0) return NO_INIT;
1055 *read = 0;
1056
1057 if (bytes == 0 && !mDataMQ) {
1058 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
1059 return OK;
1060 }
1061
1062 status_t status;
1063 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
1064 return status;
1065 }
1066
1067 ReadParameters params;
1068 params.command = ReadCommand::READ;
1069 params.params.read = bytes;
1070 status = callReaderThread(params, "read",
1071 [&](const ReadStatus& readStatus) {
1072 const size_t availToRead = mDataMQ->availableToRead();
1073 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
1074 ALOGE("data message queue read failed for \"read\"");
1075 }
1076 ALOGW_IF(availToRead != readStatus.reply.read,
1077 "HAL read report inconsistent: mq = %d, status = %d",
1078 (int32_t)availToRead, (int32_t)readStatus.reply.read);
1079 *read = readStatus.reply.read;
1080 });
1081 mStreamPowerLog.log(buffer, *read);
1082 return status;
1083}
1084
1085status_t StreamInHalHidl::callReaderThread(
1086 const ReadParameters& params, const char* cmdName,
1087 StreamInHalHidl::ReaderCallback callback) {
1088 if (!mCommandMQ->write(&params)) {
1089 ALOGW("command message queue write failed");
1090 return -EAGAIN;
1091 }
1092 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
1093
1094 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
1095 uint32_t efState = 0;
1096retry:
1097 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
1098 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
1099 ReadStatus readStatus;
1100 readStatus.retval = Result::NOT_INITIALIZED;
1101 if (!mStatusMQ->read(&readStatus)) {
1102 ALOGE("status message read failed for \"%s\"", cmdName);
1103 }
1104 if (readStatus.retval == Result::OK) {
1105 ret = OK;
1106 callback(readStatus);
1107 } else {
1108 ret = processReturn(cmdName, readStatus.retval);
1109 }
1110 return ret;
1111 }
1112 if (ret == -EAGAIN || ret == -EINTR) {
1113 // Spurious wakeup. This normally retries no more than once.
1114 goto retry;
1115 }
1116 return ret;
1117}
1118
1119status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
1120 std::unique_ptr<CommandMQ> tempCommandMQ;
1121 std::unique_ptr<DataMQ> tempDataMQ;
1122 std::unique_ptr<StatusMQ> tempStatusMQ;
1123 Result retval;
1124 pid_t halThreadPid, halThreadTid;
1125 Return<void> ret = mStream->prepareForReading(
1126 1, bufferSize,
1127 [&](Result r,
1128 const CommandMQ::Descriptor& commandMQ,
1129 const DataMQ::Descriptor& dataMQ,
1130 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001131 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001132 retval = r;
1133 if (retval == Result::OK) {
1134 tempCommandMQ.reset(new CommandMQ(commandMQ));
1135 tempDataMQ.reset(new DataMQ(dataMQ));
1136 tempStatusMQ.reset(new StatusMQ(statusMQ));
1137 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
1138 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
1139 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001140#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001141 halThreadPid = halThreadInfo.pid;
1142 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001143#else
1144 halThreadTid = halThreadInfo;
1145#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001146 }
1147 });
1148 if (!ret.isOk() || retval != Result::OK) {
1149 return processReturn("prepareForReading", ret, retval);
1150 }
1151 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
1152 !tempDataMQ || !tempDataMQ->isValid() ||
1153 !tempStatusMQ || !tempStatusMQ->isValid() ||
1154 !mEfGroup) {
1155 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
1156 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
1157 "Command message queue for writing is invalid");
1158 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
1159 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
1160 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
1161 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
1162 "Status message queue for reading is invalid");
1163 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
1164 return NO_INIT;
1165 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001166#if MAJOR_VERSION >= 7
1167 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
1168 return status;
1169 }
1170#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001171 requestHalThreadPriority(halThreadPid, halThreadTid);
1172
1173 mCommandMQ = std::move(tempCommandMQ);
1174 mDataMQ = std::move(tempDataMQ);
1175 mStatusMQ = std::move(tempStatusMQ);
1176 mReaderClient = gettid();
1177 return OK;
1178}
1179
1180status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
Andy Hung224f82f2022-03-22 00:00:49 -07001181 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001182 if (mStream == 0) return NO_INIT;
1183 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
1184}
1185
1186status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
Shunkai Yaoc6308712023-02-22 17:53:04 +00001187 // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001188 if (mStream == 0) return NO_INIT;
1189 if (mReaderClient == gettid() && mCommandMQ) {
1190 ReadParameters params;
1191 params.command = ReadCommand::GET_CAPTURE_POSITION;
1192 return callReaderThread(params, "getCapturePosition",
1193 [&](const ReadStatus& readStatus) {
1194 *frames = readStatus.reply.capturePosition.frames;
1195 *time = readStatus.reply.capturePosition.time;
1196 });
1197 } else {
1198 Result retval;
1199 Return<void> ret = mStream->getCapturePosition(
1200 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
1201 retval = r;
1202 if (retval == Result::OK) {
1203 *frames = hidlFrames;
1204 *time = hidlTime;
1205 }
1206 });
1207 return processReturn("getCapturePosition", ret, retval);
1208 }
1209}
1210
Kevin Rocard070e7512018-05-22 09:29:13 -07001211#if MAJOR_VERSION == 2
1212status_t StreamInHalHidl::getActiveMicrophones(
Mikhail Naganov2a6a3012023-02-13 11:45:03 -08001213 std::vector<media::MicrophoneInfoFw> *microphones __unused) {
Kevin Rocard070e7512018-05-22 09:29:13 -07001214 if (mStream == 0) return NO_INIT;
1215 return INVALID_OPERATION;
1216}
1217
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001218status_t StreamInHalHidl::updateSinkMetadata(
1219 const StreamInHalInterface::SinkMetadata& /* sinkMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -07001220 // Audio HAL V2.0 does not support propagating sink metadata
1221 return INVALID_OPERATION;
1222}
1223
Kevin Rocard3d48dce2018-11-08 17:16:57 -08001224#elif MAJOR_VERSION >= 4
jiabin9ff780e2018-03-19 18:19:52 -07001225status_t StreamInHalHidl::getActiveMicrophones(
Mikhail Naganov2a6a3012023-02-13 11:45:03 -08001226 std::vector<media::MicrophoneInfoFw> *microphonesInfo) {
Andy Hung224f82f2022-03-22 00:00:49 -07001227 TIME_CHECK();
jiabin9ff780e2018-03-19 18:19:52 -07001228 if (!mStream) return NO_INIT;
1229 Result retval;
1230 Return<void> ret = mStream->getActiveMicrophones(
1231 [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
1232 retval = r;
1233 for (size_t k = 0; k < micArrayHal.size(); k++) {
Mikhail Naganov2a6a3012023-02-13 11:45:03 -08001234 // Convert via legacy.
jiabin9ff780e2018-03-19 18:19:52 -07001235 audio_microphone_characteristic_t dst;
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001236 (void)CoreUtils::microphoneInfoToHal(micArrayHal[k], &dst);
Mikhail Naganov2a6a3012023-02-13 11:45:03 -08001237 auto conv = legacy2aidl_audio_microphone_characteristic_t_MicrophoneInfoFw(dst);
1238 if (conv.ok()) {
1239 microphonesInfo->push_back(conv.value());
1240 } else {
1241 ALOGW("getActiveMicrophones: could not convert %s to AIDL: %d",
1242 toString(micArrayHal[k]).c_str(), conv.error());
1243 microphonesInfo->push_back(media::MicrophoneInfoFw{});
1244 }
jiabin9ff780e2018-03-19 18:19:52 -07001245 }
1246 });
1247 return processReturn("getActiveMicrophones", ret, retval);
1248}
1249
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001250status_t StreamInHalHidl::updateSinkMetadata(const
1251 StreamInHalInterface::SinkMetadata& sinkMetadata) {
Andy Hung224f82f2022-03-22 00:00:49 -07001252 TIME_CHECK();
Mikhail Naganov6718c392022-01-27 22:17:21 +00001253#if MAJOR_VERSION == 4
1254 ::android::hardware::audio::CORE_TYPES_CPP_VERSION::SinkMetadata hidlMetadata;
1255#else
1256 ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::SinkMetadata hidlMetadata;
1257#endif
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001258 if (status_t status = CoreUtils::sinkMetadataFromHalV7(
1259 sinkMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
1260 status != OK) {
1261 return status;
1262 }
1263 return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -07001264}
Kevin Rocard070e7512018-05-22 09:29:13 -07001265#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -07001266
Paul McLean03a6e6a2018-12-04 10:54:13 -07001267#if MAJOR_VERSION < 5
Paul McLean12340082019-03-19 09:35:05 -06001268status_t StreamInHalHidl::setPreferredMicrophoneDirection(
1269 audio_microphone_direction_t direction __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001270 if (mStream == 0) return NO_INIT;
1271 return INVALID_OPERATION;
1272}
1273
Paul McLean12340082019-03-19 09:35:05 -06001274status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001275 if (mStream == 0) return NO_INIT;
1276 return INVALID_OPERATION;
1277}
1278#else
Paul McLean12340082019-03-19 09:35:05 -06001279status_t StreamInHalHidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
Andy Hung224f82f2022-03-22 00:00:49 -07001280 TIME_CHECK();
Paul McLean03a6e6a2018-12-04 10:54:13 -07001281 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001282 return processReturn("setPreferredMicrophoneDirection",
1283 mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction)));
Paul McLean03a6e6a2018-12-04 10:54:13 -07001284}
1285
Paul McLean12340082019-03-19 09:35:05 -06001286status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom) {
Andy Hung224f82f2022-03-22 00:00:49 -07001287 TIME_CHECK();
Paul McLean03a6e6a2018-12-04 10:54:13 -07001288 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001289 return processReturn("setPreferredMicrophoneFieldDimension",
Paul McLean03a6e6a2018-12-04 10:54:13 -07001290 mStream->setMicrophoneFieldDimension(zoom));
1291}
1292#endif
1293
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001294} // namespace android