blob: 2c289e1581e3bf5a575e53c483c5cac2f3280033 [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>
27
Mikhail Naganov6718c392022-01-27 22:17:21 +000028#include PATH(android/hardware/audio/CORE_TYPES_FILE_VERSION/IStreamOutCallback.h)
Mikhail Naganov247b5f92021-01-15 19:16:12 +000029#include <HidlUtils.h>
30#include <util/CoreUtils.h>
31
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080032#include "DeviceHalHidl.h"
Mikhail Naganov247b5f92021-01-15 19:16:12 +000033#include "ParameterUtils.h"
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080034#include "StreamHalHidl.h"
35
Mikhail Naganov6718c392022-01-27 22:17:21 +000036using ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::implementation::HidlUtils;
37using ::android::hardware::audio::CORE_TYPES_CPP_VERSION::implementation::CoreUtils;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080038using ::android::hardware::MQDescriptorSync;
39using ::android::hardware::Return;
40using ::android::hardware::Void;
Kevin Rocarddf9b4202018-05-10 19:56:08 -070041
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080042namespace android {
43
Mikhail Naganovaccbe8a2022-02-03 23:45:36 +000044using ReadCommand = ::android::hardware::audio::CORE_TYPES_CPP_VERSION::IStreamIn::ReadCommand;
Mikhail Naganov9ccaa162018-12-12 10:27:29 -080045
Mikhail Naganov6718c392022-01-27 22:17:21 +000046using namespace ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION;
47using namespace ::android::hardware::audio::CORE_TYPES_CPP_VERSION;
Mikhail Naganov9ccaa162018-12-12 10:27:29 -080048
Andy Hung224f82f2022-03-22 00:00:49 -070049StreamHalHidl::StreamHalHidl(std::string_view className, IStream *stream)
Mikhail Naganov288a3432022-03-25 00:29:56 +000050 : CoreConversionHelperHidl(className),
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080051 mStream(stream),
52 mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT),
53 mCachedBufferSize(0){
54
55 // Instrument audio signal power logging.
56 // Note: This assumes channel mask, format, and sample rate do not change after creation.
Mikhail Naganov247b5f92021-01-15 19:16:12 +000057 audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
58 if (/* mStreamPowerLog.isUserDebugOrEngBuild() && */
Mikhail Naganov560637e2021-03-31 22:40:13 +000059 StreamHalHidl::getAudioProperties(&config) == NO_ERROR) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +000060 mStreamPowerLog.init(config.sample_rate, config.channel_mask, config.format);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080061 }
62}
63
Andy Hungacb5b982021-01-20 10:12:00 -080064StreamHalHidl::~StreamHalHidl() {
65 // The last step is to flush all binder commands so that the deletion
66 // of IStreamIn / IStreamOut (mStream) is issued with less delay. See b/35394629.
67 hardware::IPCThreadState::self()->flushCommands();
68}
69
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080070status_t StreamHalHidl::getBufferSize(size_t *size) {
Andy Hung224f82f2022-03-22 00:00:49 -070071 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080072 if (!mStream) return NO_INIT;
73 status_t status = processReturn("getBufferSize", mStream->getBufferSize(), size);
74 if (status == OK) {
75 mCachedBufferSize = *size;
76 }
77 return status;
78}
79
Mikhail Naganov560637e2021-03-31 22:40:13 +000080status_t StreamHalHidl::getAudioProperties(audio_config_base_t *configBase) {
Andy Hung224f82f2022-03-22 00:00:49 -070081 TIME_CHECK();
Mikhail Naganov560637e2021-03-31 22:40:13 +000082 *configBase = AUDIO_CONFIG_BASE_INITIALIZER;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080083 if (!mStream) return NO_INIT;
Mikhail Naganov247b5f92021-01-15 19:16:12 +000084#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080085 Return<void> ret = mStream->getAudioProperties(
Kevin Rocardb9cfbf12018-02-23 19:11:06 -080086 [&](uint32_t sr, auto m, auto f) {
Mikhail Naganov560637e2021-03-31 22:40:13 +000087 configBase->sample_rate = sr;
88 configBase->channel_mask = static_cast<audio_channel_mask_t>(m);
89 configBase->format = static_cast<audio_format_t>(f);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080090 });
91 return processReturn("getAudioProperties", ret);
Mikhail Naganov247b5f92021-01-15 19:16:12 +000092#else
93 Result retval;
94 status_t conversionStatus = BAD_VALUE;
Mikhail Naganov247b5f92021-01-15 19:16:12 +000095 Return<void> ret = mStream->getAudioProperties(
96 [&](Result r, const AudioConfigBase& config) {
97 retval = r;
98 if (retval == Result::OK) {
Mikhail Naganov560637e2021-03-31 22:40:13 +000099 conversionStatus = HidlUtils::audioConfigBaseToHal(config, configBase);
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000100 }
101 });
102 if (status_t status = processReturn("getAudioProperties", ret, retval); status == NO_ERROR) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000103 return conversionStatus;
104 } else {
105 return status;
106 }
107#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800108}
109
110status_t StreamHalHidl::setParameters(const String8& kvPairs) {
Andy Hung224f82f2022-03-22 00:00:49 -0700111 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800112 if (!mStream) return NO_INIT;
113 hidl_vec<ParameterValue> hidlParams;
114 status_t status = parametersFromHal(kvPairs, &hidlParams);
115 if (status != OK) return status;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800116 return processReturn("setParameters",
Dean Wheatley7b417a22019-01-31 20:39:42 +1100117 utils::setParameters(mStream, {} /* context */, hidlParams));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800118}
119
120status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
Andy Hung224f82f2022-03-22 00:00:49 -0700121 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800122 values->clear();
123 if (!mStream) return NO_INIT;
124 hidl_vec<hidl_string> hidlKeys;
125 status_t status = keysFromHal(keys, &hidlKeys);
126 if (status != OK) return status;
127 Result retval;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800128 Return<void> ret = utils::getParameters(
129 mStream,
130 {} /* context */,
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800131 hidlKeys,
132 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
133 retval = r;
134 if (retval == Result::OK) {
135 parametersToHal(parameters, values);
136 }
137 });
138 return processReturn("getParameters", ret, retval);
139}
140
141status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
Andy Hung224f82f2022-03-22 00:00:49 -0700142 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800143 if (!mStream) return NO_INIT;
Mikhail Naganov6718c392022-01-27 22:17:21 +0000144 return processReturn("addEffect", mStream->addEffect(effect->effectId()));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800145}
146
147status_t StreamHalHidl::removeEffect(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 Naganov6718c392022-01-27 22:17:21 +0000150 return processReturn("removeEffect", mStream->removeEffect(effect->effectId()));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800151}
152
153status_t StreamHalHidl::standby() {
Andy Hung224f82f2022-03-22 00:00:49 -0700154 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800155 if (!mStream) return NO_INIT;
156 return processReturn("standby", mStream->standby());
157}
158
Andy Hung61589a42021-06-16 09:37:53 -0700159status_t StreamHalHidl::dump(int fd, const Vector<String16>& args) {
Andy Hung224f82f2022-03-22 00:00:49 -0700160 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800161 if (!mStream) return NO_INIT;
162 native_handle_t* hidlHandle = native_handle_create(1, 0);
163 hidlHandle->data[0] = fd;
Andy Hung61589a42021-06-16 09:37:53 -0700164 hidl_vec<hidl_string> hidlArgs;
165 argsFromHal(args, &hidlArgs);
166 Return<void> ret = mStream->debug(hidlHandle, hidlArgs);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800167 native_handle_delete(hidlHandle);
Andy Hunge72ff022021-08-16 10:16:15 -0700168
169 // TODO(b/111997867, b/177271958) Workaround - remove when fixed.
170 // A Binder transmitted fd may not close immediately due to a race condition b/111997867
171 // when the remote binder thread removes the last refcount to the fd blocks in the
172 // kernel for binder activity. We send a Binder ping() command to unblock the thread
173 // and complete the fd close / release.
174 //
175 // See DeviceHalHidl::dump(), EffectHalHidl::dump(), StreamHalHidl::dump(),
176 // EffectsFactoryHalHidl::dumpEffects().
177
178 (void)mStream->ping(); // synchronous Binder call
179
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800180 mStreamPowerLog.dump(fd);
181 return processReturn("dump", ret);
182}
183
184status_t StreamHalHidl::start() {
Andy Hung224f82f2022-03-22 00:00:49 -0700185 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800186 if (!mStream) return NO_INIT;
187 return processReturn("start", mStream->start());
188}
189
190status_t StreamHalHidl::stop() {
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("stop", mStream->stop());
194}
195
196status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
197 struct audio_mmap_buffer_info *info) {
Andy Hung224f82f2022-03-22 00:00:49 -0700198 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800199 Result retval;
200 Return<void> ret = mStream->createMmapBuffer(
201 minSizeFrames,
202 [&](Result r, const MmapBufferInfo& hidlInfo) {
203 retval = r;
204 if (retval == Result::OK) {
205 const native_handle *handle = hidlInfo.sharedMemory.handle();
206 if (handle->numFds > 0) {
207 info->shared_memory_fd = handle->data[0];
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800208#if MAJOR_VERSION >= 4
Kevin Rocard734334f2018-07-12 19:37:41 -0700209 info->flags = audio_mmap_buffer_flag(hidlInfo.flags);
210#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800211 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
Kevin Rocard734334f2018-07-12 19:37:41 -0700212 // Negative buffer size frame was a hack in O and P to
213 // indicate that the buffer is shareable to applications
214 if (info->buffer_size_frames < 0) {
215 info->buffer_size_frames *= -1;
216 info->flags = audio_mmap_buffer_flag(
217 info->flags | AUDIO_MMAP_APPLICATION_SHAREABLE);
218 }
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800219 info->burst_size_frames = hidlInfo.burstSizeFrames;
220 // info->shared_memory_address is not needed in HIDL context
221 info->shared_memory_address = NULL;
222 } else {
223 retval = Result::NOT_INITIALIZED;
224 }
225 }
226 });
227 return processReturn("createMmapBuffer", ret, retval);
228}
229
230status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
Andy Hung224f82f2022-03-22 00:00:49 -0700231 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800232 Result retval;
233 Return<void> ret = mStream->getMmapPosition(
234 [&](Result r, const MmapPosition& hidlPosition) {
235 retval = r;
236 if (retval == Result::OK) {
237 position->time_nanoseconds = hidlPosition.timeNanoseconds;
238 position->position_frames = hidlPosition.positionFrames;
239 }
240 });
241 return processReturn("getMmapPosition", ret, retval);
242}
243
244status_t StreamHalHidl::setHalThreadPriority(int priority) {
245 mHalThreadPriority = priority;
246 return OK;
247}
248
249status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
250 if (mCachedBufferSize != 0) {
251 *size = mCachedBufferSize;
252 return OK;
253 }
254 return getBufferSize(size);
255}
256
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000257status_t StreamHalHidl::getHalPid(pid_t *pid) {
258 using ::android::hidl::base::V1_0::DebugInfo;
259 using ::android::hidl::manager::V1_0::IServiceManager;
Andy Hung224f82f2022-03-22 00:00:49 -0700260 TIME_CHECK();
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000261 DebugInfo debugInfo;
262 auto ret = mStream->getDebugInfo([&] (const auto &info) {
263 debugInfo = info;
264 });
265 if (!ret.isOk()) {
266 return INVALID_OPERATION;
267 }
268 if (debugInfo.pid != (int)IServiceManager::PidConstant::NO_PID) {
269 *pid = debugInfo.pid;
270 return NO_ERROR;
271 }
272 return NAME_NOT_FOUND;
273}
274
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800275bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
276 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
277 return true;
278 }
279 int err = requestPriority(
280 threadPid, threadId,
281 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
282 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
283 mHalThreadPriority, threadPid, threadId, err);
284 // Audio will still work, but latency will be higher and sometimes unacceptable.
285 return err == 0;
286}
287
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800288status_t StreamHalHidl::legacyCreateAudioPatch(const struct audio_port_config& port,
289 std::optional<audio_source_t> source,
290 audio_devices_t type) {
Andy Hung224f82f2022-03-22 00:00:49 -0700291 TIME_CHECK();
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800292 LOG_ALWAYS_FATAL_IF(port.type != AUDIO_PORT_TYPE_DEVICE, "port type must be device");
Ytai Ben-Tsvidb6f8982022-02-07 12:06:23 -0800293 unique_malloced_ptr<char> address;
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800294 if (strcmp(port.ext.device.address, "") != 0) {
295 // FIXME: we only support address on first sink with HAL version < 3.0
Ytai Ben-Tsvidb6f8982022-02-07 12:06:23 -0800296 address.reset(
297 audio_device_address_to_parameter(port.ext.device.type, port.ext.device.address));
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800298 } else {
Ytai Ben-Tsvidb6f8982022-02-07 12:06:23 -0800299 address.reset((char*)calloc(1, 1));
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800300 }
Ytai Ben-Tsvidb6f8982022-02-07 12:06:23 -0800301 AudioParameter param = AudioParameter(String8(address.get()));
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800302 param.addInt(String8(AudioParameter::keyRouting), (int)type);
303 if (source.has_value()) {
304 param.addInt(String8(AudioParameter::keyInputSource), (int)source.value());
305 }
306 return setParameters(param.toString());
307}
308
309status_t StreamHalHidl::legacyReleaseAudioPatch() {
Andy Hung224f82f2022-03-22 00:00:49 -0700310 TIME_CHECK();
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800311 AudioParameter param;
312 param.addInt(String8(AudioParameter::keyRouting), 0);
313 return setParameters(param.toString());
314}
315
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800316namespace {
317
318/* Notes on callback ownership.
319
320This is how (Hw)Binder ownership model looks like. The server implementation
321is owned by Binder framework (via sp<>). Proxies are owned by clients.
322When the last proxy disappears, Binder framework releases the server impl.
323
324Thus, it is not needed to keep any references to StreamOutCallback (this is
325the server impl) -- it will live as long as HAL server holds a strong ref to
326IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
327from the destructor of StreamOutHalHidl.
328
329The callback only keeps a weak reference to the stream. The stream is owned
330by AudioFlinger.
331
332*/
333
334struct StreamOutCallback : public IStreamOutCallback {
335 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
336
337 // IStreamOutCallback implementation
338 Return<void> onWriteReady() override {
339 sp<StreamOutHalHidl> stream = mStream.promote();
340 if (stream != 0) {
341 stream->onWriteReady();
342 }
343 return Void();
344 }
345
346 Return<void> onDrainReady() override {
347 sp<StreamOutHalHidl> stream = mStream.promote();
348 if (stream != 0) {
349 stream->onDrainReady();
350 }
351 return Void();
352 }
353
354 Return<void> onError() override {
355 sp<StreamOutHalHidl> stream = mStream.promote();
356 if (stream != 0) {
357 stream->onError();
358 }
359 return Void();
360 }
361
362 private:
Andy Hung638f45b2021-01-18 20:02:56 -0800363 const wp<StreamOutHalHidl> mStream;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800364};
365
366} // namespace
367
Mikhail Naganov6718c392022-01-27 22:17:21 +0000368StreamOutHalHidl::StreamOutHalHidl(
369 const sp<::android::hardware::audio::CPP_VERSION::IStreamOut>& stream)
Andy Hung224f82f2022-03-22 00:00:49 -0700370 : StreamHalHidl("StreamOutHalHidl", stream.get())
371 , mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800372}
373
374StreamOutHalHidl::~StreamOutHalHidl() {
375 if (mStream != 0) {
Andy Hung638f45b2021-01-18 20:02:56 -0800376 if (mCallback.load().unsafe_get()) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800377 processReturn("clearCallback", mStream->clearCallback());
378 }
jiabinf6eb4c32020-02-25 14:06:25 -0800379#if MAJOR_VERSION >= 6
Andy Hung638f45b2021-01-18 20:02:56 -0800380 if (mEventCallback.load().unsafe_get() != nullptr) {
jiabinf6eb4c32020-02-25 14:06:25 -0800381 processReturn("setEventCallback",
382 mStream->setEventCallback(nullptr));
383 }
384#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800385 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800386 }
Andy Hung638f45b2021-01-18 20:02:56 -0800387 mCallback = nullptr;
388 mEventCallback = nullptr;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800389 if (mEfGroup) {
390 EventFlag::deleteEventFlag(&mEfGroup);
391 }
392}
393
394status_t StreamOutHalHidl::getFrameSize(size_t *size) {
Andy Hung224f82f2022-03-22 00:00:49 -0700395 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800396 if (mStream == 0) return NO_INIT;
397 return processReturn("getFrameSize", mStream->getFrameSize(), size);
398}
399
400status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
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 if (mWriterClient == gettid() && mCommandMQ) {
404 return callWriterThread(
405 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
406 [&](const WriteStatus& writeStatus) {
407 *latency = writeStatus.reply.latencyMs;
408 });
409 } else {
410 return processReturn("getLatency", mStream->getLatency(), latency);
411 }
412}
413
414status_t StreamOutHalHidl::setVolume(float left, float right) {
Andy Hung224f82f2022-03-22 00:00:49 -0700415 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800416 if (mStream == 0) return NO_INIT;
417 return processReturn("setVolume", mStream->setVolume(left, right));
418}
419
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800420#if MAJOR_VERSION == 2
421status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
Andy Hung224f82f2022-03-22 00:00:49 -0700422 TIME_CHECK();
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800423 if (mStream == 0) return NO_INIT;
424 std::vector<ParameterValue> parameters;
425 String8 halParameters;
426 parameters.push_back({AudioParameter::keyPresentationId, std::to_string(presentationId)});
427 parameters.push_back({AudioParameter::keyProgramId, std::to_string(programId)});
428 parametersToHal(hidl_vec<ParameterValue>(parameters), &halParameters);
429 return setParameters(halParameters);
430}
Kevin Rocard1cf6b4d2018-11-20 18:05:44 -0800431#elif MAJOR_VERSION >= 4
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800432status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
Andy Hung224f82f2022-03-22 00:00:49 -0700433 TIME_CHECK();
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800434 if (mStream == 0) return NO_INIT;
435 return processReturn("selectPresentation",
436 mStream->selectPresentation(presentationId, programId));
437}
438#endif
439
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800440status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
Andy Hung308aaa52022-07-11 12:07:06 -0700441 // TIME_CHECK(); // TODO(b/238654698) reenable only when optimized.
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800442 if (mStream == 0) return NO_INIT;
443 *written = 0;
444
445 if (bytes == 0 && !mDataMQ) {
446 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
Andy Hung638f45b2021-01-18 20:02:56 -0800447 ALOGW_IF(mCallback.load().unsafe_get(), "First call to async write with 0 bytes");
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800448 return OK;
449 }
450
451 status_t status;
452 if (!mDataMQ) {
453 // In case if playback starts close to the end of a compressed track, the bytes
454 // that need to be written is less than the actual buffer size. Need to use
455 // full buffer size for the MQ since otherwise after seeking back to the middle
456 // data will be truncated.
457 size_t bufferSize;
458 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
459 return status;
460 }
461 if (bytes > bufferSize) bufferSize = bytes;
462 if ((status = prepareForWriting(bufferSize)) != OK) {
463 return status;
464 }
465 }
466
467 status = callWriterThread(
468 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
469 [&] (const WriteStatus& writeStatus) {
470 *written = writeStatus.reply.written;
471 // Diagnostics of the cause of b/35813113.
472 ALOGE_IF(*written > bytes,
473 "hal reports more bytes written than asked for: %lld > %lld",
474 (long long)*written, (long long)bytes);
475 });
476 mStreamPowerLog.log(buffer, *written);
477 return status;
478}
479
480status_t StreamOutHalHidl::callWriterThread(
481 WriteCommand cmd, const char* cmdName,
482 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
483 if (!mCommandMQ->write(&cmd)) {
484 ALOGE("command message queue write failed for \"%s\"", cmdName);
485 return -EAGAIN;
486 }
487 if (data != nullptr) {
488 size_t availableToWrite = mDataMQ->availableToWrite();
489 if (dataSize > availableToWrite) {
490 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
491 (long long)dataSize, (long long)availableToWrite);
492 dataSize = availableToWrite;
493 }
494 if (!mDataMQ->write(data, dataSize)) {
495 ALOGE("data message queue write failed for \"%s\"", cmdName);
496 }
497 }
498 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
499
500 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
501 uint32_t efState = 0;
502retry:
503 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
504 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
505 WriteStatus writeStatus;
506 writeStatus.retval = Result::NOT_INITIALIZED;
507 if (!mStatusMQ->read(&writeStatus)) {
508 ALOGE("status message read failed for \"%s\"", cmdName);
509 }
510 if (writeStatus.retval == Result::OK) {
511 ret = OK;
512 callback(writeStatus);
513 } else {
514 ret = processReturn(cmdName, writeStatus.retval);
515 }
516 return ret;
517 }
518 if (ret == -EAGAIN || ret == -EINTR) {
519 // Spurious wakeup. This normally retries no more than once.
520 goto retry;
521 }
522 return ret;
523}
524
525status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
526 std::unique_ptr<CommandMQ> tempCommandMQ;
527 std::unique_ptr<DataMQ> tempDataMQ;
528 std::unique_ptr<StatusMQ> tempStatusMQ;
529 Result retval;
530 pid_t halThreadPid, halThreadTid;
531 Return<void> ret = mStream->prepareForWriting(
532 1, bufferSize,
533 [&](Result r,
534 const CommandMQ::Descriptor& commandMQ,
535 const DataMQ::Descriptor& dataMQ,
536 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000537 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800538 retval = r;
539 if (retval == Result::OK) {
540 tempCommandMQ.reset(new CommandMQ(commandMQ));
541 tempDataMQ.reset(new DataMQ(dataMQ));
542 tempStatusMQ.reset(new StatusMQ(statusMQ));
543 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
544 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
545 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000546#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800547 halThreadPid = halThreadInfo.pid;
548 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000549#else
550 halThreadTid = halThreadInfo;
551#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800552 }
553 });
554 if (!ret.isOk() || retval != Result::OK) {
555 return processReturn("prepareForWriting", ret, retval);
556 }
557 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
558 !tempDataMQ || !tempDataMQ->isValid() ||
559 !tempStatusMQ || !tempStatusMQ->isValid() ||
560 !mEfGroup) {
561 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
562 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
563 "Command message queue for writing is invalid");
564 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
565 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
566 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
567 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
568 "Status message queue for writing is invalid");
569 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
570 return NO_INIT;
571 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000572#if MAJOR_VERSION >= 7
573 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
574 return status;
575 }
576#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800577 requestHalThreadPriority(halThreadPid, halThreadTid);
578
579 mCommandMQ = std::move(tempCommandMQ);
580 mDataMQ = std::move(tempDataMQ);
581 mStatusMQ = std::move(tempStatusMQ);
582 mWriterClient = gettid();
583 return OK;
584}
585
586status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
Andy Hung308aaa52022-07-11 12:07:06 -0700587 // TIME_CHECK(); // TODO(b/238654698) reenable only when optimized.
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800588 if (mStream == 0) return NO_INIT;
589 Result retval;
590 Return<void> ret = mStream->getRenderPosition(
591 [&](Result r, uint32_t d) {
592 retval = r;
593 if (retval == Result::OK) {
594 *dspFrames = d;
595 }
596 });
597 return processReturn("getRenderPosition", ret, retval);
598}
599
600status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
Andy Hung224f82f2022-03-22 00:00:49 -0700601 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800602 if (mStream == 0) return NO_INIT;
603 Result retval;
604 Return<void> ret = mStream->getNextWriteTimestamp(
605 [&](Result r, int64_t t) {
606 retval = r;
607 if (retval == Result::OK) {
608 *timestamp = t;
609 }
610 });
611 return processReturn("getRenderPosition", ret, retval);
612}
613
614status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
Andy Hung224f82f2022-03-22 00:00:49 -0700615 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800616 if (mStream == 0) return NO_INIT;
617 status_t status = processReturn(
618 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
619 if (status == OK) {
620 mCallback = callback;
621 }
622 return status;
623}
624
625status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
Andy Hung224f82f2022-03-22 00:00:49 -0700626 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800627 if (mStream == 0) return NO_INIT;
628 Return<void> ret = mStream->supportsPauseAndResume(
629 [&](bool p, bool r) {
630 *supportsPause = p;
631 *supportsResume = r;
632 });
633 return processReturn("supportsPauseAndResume", ret);
634}
635
636status_t StreamOutHalHidl::pause() {
Andy Hung224f82f2022-03-22 00:00:49 -0700637 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800638 if (mStream == 0) return NO_INIT;
639 return processReturn("pause", mStream->pause());
640}
641
642status_t StreamOutHalHidl::resume() {
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->resume());
646}
647
648status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
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("supportsDrain", mStream->supportsDrain(), supportsDrain);
652}
653
654status_t StreamOutHalHidl::drain(bool earlyNotify) {
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(
658 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
659}
660
661status_t StreamOutHalHidl::flush() {
Andy Hung224f82f2022-03-22 00:00:49 -0700662 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800663 if (mStream == 0) return NO_INIT;
664 return processReturn("pause", mStream->flush());
665}
666
667status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
Andy Hung308aaa52022-07-11 12:07:06 -0700668 // TIME_CHECK(); // TODO(b/238654698) reenable only when optimized.
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800669 if (mStream == 0) return NO_INIT;
670 if (mWriterClient == gettid() && mCommandMQ) {
671 return callWriterThread(
672 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
673 [&](const WriteStatus& writeStatus) {
674 *frames = writeStatus.reply.presentationPosition.frames;
675 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
676 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
677 });
678 } else {
679 Result retval;
680 Return<void> ret = mStream->getPresentationPosition(
681 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
682 retval = r;
683 if (retval == Result::OK) {
684 *frames = hidlFrames;
685 timestamp->tv_sec = hidlTimeStamp.tvSec;
686 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
687 }
688 });
689 return processReturn("getPresentationPosition", ret, retval);
690 }
691}
692
Kevin Rocard070e7512018-05-22 09:29:13 -0700693#if MAJOR_VERSION == 2
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800694status_t StreamOutHalHidl::updateSourceMetadata(
695 const StreamOutHalInterface::SourceMetadata& /* sourceMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700696 // Audio HAL V2.0 does not support propagating source metadata
697 return INVALID_OPERATION;
698}
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800699#elif MAJOR_VERSION >= 4
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800700status_t StreamOutHalHidl::updateSourceMetadata(
701 const StreamOutHalInterface::SourceMetadata& sourceMetadata) {
Andy Hung224f82f2022-03-22 00:00:49 -0700702 TIME_CHECK();
Mikhail Naganov6718c392022-01-27 22:17:21 +0000703#if MAJOR_VERSION == 4
704 ::android::hardware::audio::CORE_TYPES_CPP_VERSION::SourceMetadata hidlMetadata;
705#else
706 ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::SourceMetadata hidlMetadata;
707#endif
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000708 if (status_t status = CoreUtils::sourceMetadataFromHalV7(
709 sourceMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
710 status != OK) {
711 return status;
712 }
713 return processReturn("updateSourceMetadata", mStream->updateSourceMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -0700714}
Kevin Rocard070e7512018-05-22 09:29:13 -0700715#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700716
jiabinf6eb4c32020-02-25 14:06:25 -0800717#if MAJOR_VERSION < 6
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800718status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode __unused) {
719 return INVALID_OPERATION;
720}
721
722status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode __unused) {
723 return INVALID_OPERATION;
724}
725
726status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB __unused) {
727 return INVALID_OPERATION;
728}
729
730status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB __unused) {
731 return INVALID_OPERATION;
732}
733
734status_t StreamOutHalHidl::getPlaybackRateParameters(
735 audio_playback_rate_t* playbackRate __unused) {
736 return INVALID_OPERATION;
737}
738
739status_t StreamOutHalHidl::setPlaybackRateParameters(
740 const audio_playback_rate_t& playbackRate __unused) {
741 return INVALID_OPERATION;
742}
743
jiabinf6eb4c32020-02-25 14:06:25 -0800744status_t StreamOutHalHidl::setEventCallback(
745 const sp<StreamOutHalInterfaceEventCallback>& callback __unused) {
746 // Codec format callback is supported starting from audio HAL V6.0
747 return INVALID_OPERATION;
748}
Eric Laurentafa586b2022-01-27 21:10:55 +0100749
jiabinf6eb4c32020-02-25 14:06:25 -0800750#else
751
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800752status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode) {
Andy Hung224f82f2022-03-22 00:00:49 -0700753 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800754 if (mStream == 0) return NO_INIT;
755 Result retval;
756 Return<void> ret = mStream->getDualMonoMode(
757 [&](Result r, DualMonoMode hidlMode) {
758 retval = r;
759 if (retval == Result::OK) {
760 *mode = static_cast<audio_dual_mono_mode_t>(hidlMode);
761 }
762 });
763 return processReturn("getDualMonoMode", ret, retval);
764}
765
766status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode) {
Andy Hung224f82f2022-03-22 00:00:49 -0700767 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800768 if (mStream == 0) return NO_INIT;
769 return processReturn(
770 "setDualMonoMode", mStream->setDualMonoMode(static_cast<DualMonoMode>(mode)));
771}
772
773status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB) {
Andy Hung224f82f2022-03-22 00:00:49 -0700774 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800775 if (mStream == 0) return NO_INIT;
776 Result retval;
777 Return<void> ret = mStream->getAudioDescriptionMixLevel(
778 [&](Result r, float hidlLeveldB) {
779 retval = r;
780 if (retval == Result::OK) {
781 *leveldB = hidlLeveldB;
782 }
783 });
784 return processReturn("getAudioDescriptionMixLevel", ret, retval);
785}
786
787status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB) {
Andy Hung224f82f2022-03-22 00:00:49 -0700788 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800789 if (mStream == 0) return NO_INIT;
790 return processReturn(
791 "setAudioDescriptionMixLevel", mStream->setAudioDescriptionMixLevel(leveldB));
792}
793
794status_t StreamOutHalHidl::getPlaybackRateParameters(audio_playback_rate_t* playbackRate) {
Andy Hung224f82f2022-03-22 00:00:49 -0700795 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800796 if (mStream == 0) return NO_INIT;
797 Result retval;
798 Return<void> ret = mStream->getPlaybackRateParameters(
799 [&](Result r, PlaybackRate hidlPlaybackRate) {
800 retval = r;
801 if (retval == Result::OK) {
802 playbackRate->mSpeed = hidlPlaybackRate.speed;
803 playbackRate->mPitch = hidlPlaybackRate.pitch;
804 playbackRate->mStretchMode =
805 static_cast<audio_timestretch_stretch_mode_t>(
806 hidlPlaybackRate.timestretchMode);
807 playbackRate->mFallbackMode =
808 static_cast<audio_timestretch_fallback_mode_t>(
809 hidlPlaybackRate.fallbackMode);
810 }
811 });
812 return processReturn("getPlaybackRateParameters", ret, retval);
813}
814
815status_t StreamOutHalHidl::setPlaybackRateParameters(const audio_playback_rate_t& playbackRate) {
Andy Hung224f82f2022-03-22 00:00:49 -0700816 TIME_CHECK();
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800817 if (mStream == 0) return NO_INIT;
818 return processReturn(
819 "setPlaybackRateParameters", mStream->setPlaybackRateParameters(
820 PlaybackRate{playbackRate.mSpeed, playbackRate.mPitch,
821 static_cast<TimestretchMode>(playbackRate.mStretchMode),
822 static_cast<TimestretchFallbackMode>(playbackRate.mFallbackMode)}));
823}
824
Mikhail Naganov6718c392022-01-27 22:17:21 +0000825#include PATH(android/hardware/audio/CORE_TYPES_FILE_VERSION/IStreamOutEventCallback.h)
jiabinf6eb4c32020-02-25 14:06:25 -0800826
827namespace {
828
829struct StreamOutEventCallback : public IStreamOutEventCallback {
830 StreamOutEventCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
831
832 // IStreamOutEventCallback implementation
833 Return<void> onCodecFormatChanged(
834 const android::hardware::hidl_vec<uint8_t>& audioMetadata) override {
835 sp<StreamOutHalHidl> stream = mStream.promote();
836 if (stream != nullptr) {
837 std::basic_string<uint8_t> metadataBs(audioMetadata.begin(), audioMetadata.end());
838 stream->onCodecFormatChanged(metadataBs);
839 }
840 return Void();
841 }
842
843 private:
844 wp<StreamOutHalHidl> mStream;
845};
846
847} // namespace
848
849status_t StreamOutHalHidl::setEventCallback(
850 const sp<StreamOutHalInterfaceEventCallback>& callback) {
Andy Hung224f82f2022-03-22 00:00:49 -0700851 TIME_CHECK();
jiabinf6eb4c32020-02-25 14:06:25 -0800852 if (mStream == nullptr) return NO_INIT;
853 mEventCallback = callback;
854 status_t status = processReturn(
855 "setEventCallback",
856 mStream->setEventCallback(
857 callback.get() == nullptr ? nullptr : new StreamOutEventCallback(this)));
858 return status;
859}
860#endif
861
Eric Laurentafa586b2022-01-27 21:10:55 +0100862#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
863using hardware::audio::V7_1::LatencyMode;
864
865status_t StreamOutHalHidl::setLatencyMode(audio_latency_mode_t mode) {
Andy Hung224f82f2022-03-22 00:00:49 -0700866 TIME_CHECK();
Eric Laurentafa586b2022-01-27 21:10:55 +0100867 if (mStream == 0) return NO_INIT;
868 return processReturn(
869 "setLatencyMode", mStream->setLatencyMode(static_cast<LatencyMode>(mode)));
870};
871
872status_t StreamOutHalHidl::getRecommendedLatencyModes(std::vector<audio_latency_mode_t> *modes) {
Andy Hung224f82f2022-03-22 00:00:49 -0700873 TIME_CHECK();
Eric Laurentafa586b2022-01-27 21:10:55 +0100874 if (!mStream) return NO_INIT;
875 Result retval;
876 Return<void> ret = mStream->getRecommendedLatencyModes(
877 [&](Result r, hidl_vec<LatencyMode> hidlModes) {
878 retval = r;
879 for (size_t i = 0; i < hidlModes.size(); i++) {
880 modes->push_back(static_cast<audio_latency_mode_t>(hidlModes[i]));
881 }
882 });
883 return processReturn("getRecommendedLatencyModes", ret, retval);
884};
885
886#include PATH(android/hardware/audio/FILE_VERSION/IStreamOutLatencyModeCallback.h)
887
888using hardware::audio::V7_1::IStreamOutLatencyModeCallback;
889
890namespace {
891struct StreamOutLatencyModeCallback : public IStreamOutLatencyModeCallback {
892 StreamOutLatencyModeCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
893
894 // IStreamOutLatencyModeCallback implementation
895 Return<void> onRecommendedLatencyModeChanged(const hidl_vec<LatencyMode>& hidlModes) override {
896 sp<StreamOutHalHidl> stream = mStream.promote();
897 if (stream != nullptr) {
898 std::vector<audio_latency_mode_t> modes;
899 for (size_t i = 0; i < hidlModes.size(); i++) {
900 modes.push_back(static_cast<audio_latency_mode_t>(hidlModes[i]));
901 }
902 stream->onRecommendedLatencyModeChanged(modes);
903 }
904 return Void();
905 }
906
907 private:
908 wp<StreamOutHalHidl> mStream;
909};
910} // namespace
911
912status_t StreamOutHalHidl::setLatencyModeCallback(
913 const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) {
Andy Hung224f82f2022-03-22 00:00:49 -0700914 TIME_CHECK();
Eric Laurentafa586b2022-01-27 21:10:55 +0100915
916 if (mStream == nullptr) return NO_INIT;
917 mLatencyModeCallback = callback;
918 status_t status = processReturn(
919 "setLatencyModeCallback",
920 mStream->setLatencyModeCallback(
921 callback.get() == nullptr ? nullptr : new StreamOutLatencyModeCallback(this)));
922 return status;
923};
924
925#else
926
927status_t StreamOutHalHidl::setLatencyMode(audio_latency_mode_t mode __unused) {
928 return INVALID_OPERATION;
929};
930
931status_t StreamOutHalHidl::getRecommendedLatencyModes(
932 std::vector<audio_latency_mode_t> *modes __unused) {
933 return INVALID_OPERATION;
934};
935
936status_t StreamOutHalHidl::setLatencyModeCallback(
937 const sp<StreamOutHalInterfaceLatencyModeCallback>& callback __unused) {
938 return INVALID_OPERATION;
939};
940
941#endif
942
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800943void StreamOutHalHidl::onWriteReady() {
Andy Hung638f45b2021-01-18 20:02:56 -0800944 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800945 if (callback == 0) return;
946 ALOGV("asyncCallback onWriteReady");
947 callback->onWriteReady();
948}
949
950void StreamOutHalHidl::onDrainReady() {
Andy Hung638f45b2021-01-18 20:02:56 -0800951 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800952 if (callback == 0) return;
953 ALOGV("asyncCallback onDrainReady");
954 callback->onDrainReady();
955}
956
957void StreamOutHalHidl::onError() {
Andy Hung638f45b2021-01-18 20:02:56 -0800958 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800959 if (callback == 0) return;
960 ALOGV("asyncCallback onError");
961 callback->onError();
962}
963
jiabinf6eb4c32020-02-25 14:06:25 -0800964void StreamOutHalHidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) {
Andy Hung638f45b2021-01-18 20:02:56 -0800965 sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.load().promote();
jiabinf6eb4c32020-02-25 14:06:25 -0800966 if (callback == nullptr) return;
967 ALOGV("asyncCodecFormatCallback %s", __func__);
968 callback->onCodecFormatChanged(metadataBs);
969}
970
Eric Laurentafa586b2022-01-27 21:10:55 +0100971void StreamOutHalHidl::onRecommendedLatencyModeChanged(
972 const std::vector<audio_latency_mode_t>& modes) {
973 sp<StreamOutHalInterfaceLatencyModeCallback> callback = mLatencyModeCallback.load().promote();
974 if (callback == nullptr) return;
975 callback->onRecommendedLatencyModeChanged(modes);
976}
977
Ytai Ben-Tsvi7e0183f2022-02-04 10:49:54 -0800978status_t StreamOutHalHidl::exit() {
979 // FIXME this is using hard-coded strings but in the future, this functionality will be
980 // converted to use audio HAL extensions required to support tunneling
981 return setParameters(String8("exiting=1"));
982}
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800983
Mikhail Naganov6718c392022-01-27 22:17:21 +0000984StreamInHalHidl::StreamInHalHidl(
Mikhail Naganovaccbe8a2022-02-03 23:45:36 +0000985 const sp<::android::hardware::audio::CORE_TYPES_CPP_VERSION::IStreamIn>& stream)
Andy Hung224f82f2022-03-22 00:00:49 -0700986 : StreamHalHidl("StreamInHalHidl", stream.get())
987 , mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800988}
989
990StreamInHalHidl::~StreamInHalHidl() {
991 if (mStream != 0) {
992 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800993 }
994 if (mEfGroup) {
995 EventFlag::deleteEventFlag(&mEfGroup);
996 }
997}
998
999status_t StreamInHalHidl::getFrameSize(size_t *size) {
Andy Hung224f82f2022-03-22 00:00:49 -07001000 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001001 if (mStream == 0) return NO_INIT;
1002 return processReturn("getFrameSize", mStream->getFrameSize(), size);
1003}
1004
1005status_t StreamInHalHidl::setGain(float gain) {
Andy Hung224f82f2022-03-22 00:00:49 -07001006 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001007 if (mStream == 0) return NO_INIT;
1008 return processReturn("setGain", mStream->setGain(gain));
1009}
1010
1011status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
Andy Hung308aaa52022-07-11 12:07:06 -07001012 // TIME_CHECK(); // TODO(b/238654698) reenable only when optimized.
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001013 if (mStream == 0) return NO_INIT;
1014 *read = 0;
1015
1016 if (bytes == 0 && !mDataMQ) {
1017 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
1018 return OK;
1019 }
1020
1021 status_t status;
1022 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
1023 return status;
1024 }
1025
1026 ReadParameters params;
1027 params.command = ReadCommand::READ;
1028 params.params.read = bytes;
1029 status = callReaderThread(params, "read",
1030 [&](const ReadStatus& readStatus) {
1031 const size_t availToRead = mDataMQ->availableToRead();
1032 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
1033 ALOGE("data message queue read failed for \"read\"");
1034 }
1035 ALOGW_IF(availToRead != readStatus.reply.read,
1036 "HAL read report inconsistent: mq = %d, status = %d",
1037 (int32_t)availToRead, (int32_t)readStatus.reply.read);
1038 *read = readStatus.reply.read;
1039 });
1040 mStreamPowerLog.log(buffer, *read);
1041 return status;
1042}
1043
1044status_t StreamInHalHidl::callReaderThread(
1045 const ReadParameters& params, const char* cmdName,
1046 StreamInHalHidl::ReaderCallback callback) {
1047 if (!mCommandMQ->write(&params)) {
1048 ALOGW("command message queue write failed");
1049 return -EAGAIN;
1050 }
1051 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
1052
1053 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
1054 uint32_t efState = 0;
1055retry:
1056 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
1057 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
1058 ReadStatus readStatus;
1059 readStatus.retval = Result::NOT_INITIALIZED;
1060 if (!mStatusMQ->read(&readStatus)) {
1061 ALOGE("status message read failed for \"%s\"", cmdName);
1062 }
1063 if (readStatus.retval == Result::OK) {
1064 ret = OK;
1065 callback(readStatus);
1066 } else {
1067 ret = processReturn(cmdName, readStatus.retval);
1068 }
1069 return ret;
1070 }
1071 if (ret == -EAGAIN || ret == -EINTR) {
1072 // Spurious wakeup. This normally retries no more than once.
1073 goto retry;
1074 }
1075 return ret;
1076}
1077
1078status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
1079 std::unique_ptr<CommandMQ> tempCommandMQ;
1080 std::unique_ptr<DataMQ> tempDataMQ;
1081 std::unique_ptr<StatusMQ> tempStatusMQ;
1082 Result retval;
1083 pid_t halThreadPid, halThreadTid;
1084 Return<void> ret = mStream->prepareForReading(
1085 1, bufferSize,
1086 [&](Result r,
1087 const CommandMQ::Descriptor& commandMQ,
1088 const DataMQ::Descriptor& dataMQ,
1089 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001090 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001091 retval = r;
1092 if (retval == Result::OK) {
1093 tempCommandMQ.reset(new CommandMQ(commandMQ));
1094 tempDataMQ.reset(new DataMQ(dataMQ));
1095 tempStatusMQ.reset(new StatusMQ(statusMQ));
1096 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
1097 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
1098 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001099#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001100 halThreadPid = halThreadInfo.pid;
1101 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001102#else
1103 halThreadTid = halThreadInfo;
1104#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001105 }
1106 });
1107 if (!ret.isOk() || retval != Result::OK) {
1108 return processReturn("prepareForReading", ret, retval);
1109 }
1110 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
1111 !tempDataMQ || !tempDataMQ->isValid() ||
1112 !tempStatusMQ || !tempStatusMQ->isValid() ||
1113 !mEfGroup) {
1114 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
1115 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
1116 "Command message queue for writing is invalid");
1117 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
1118 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
1119 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
1120 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
1121 "Status message queue for reading is invalid");
1122 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
1123 return NO_INIT;
1124 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001125#if MAJOR_VERSION >= 7
1126 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
1127 return status;
1128 }
1129#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001130 requestHalThreadPriority(halThreadPid, halThreadTid);
1131
1132 mCommandMQ = std::move(tempCommandMQ);
1133 mDataMQ = std::move(tempDataMQ);
1134 mStatusMQ = std::move(tempStatusMQ);
1135 mReaderClient = gettid();
1136 return OK;
1137}
1138
1139status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
Andy Hung224f82f2022-03-22 00:00:49 -07001140 TIME_CHECK();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001141 if (mStream == 0) return NO_INIT;
1142 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
1143}
1144
1145status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
Andy Hung308aaa52022-07-11 12:07:06 -07001146 // TIME_CHECK(); // TODO(b/238654698) reenable only when optimized.
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001147 if (mStream == 0) return NO_INIT;
1148 if (mReaderClient == gettid() && mCommandMQ) {
1149 ReadParameters params;
1150 params.command = ReadCommand::GET_CAPTURE_POSITION;
1151 return callReaderThread(params, "getCapturePosition",
1152 [&](const ReadStatus& readStatus) {
1153 *frames = readStatus.reply.capturePosition.frames;
1154 *time = readStatus.reply.capturePosition.time;
1155 });
1156 } else {
1157 Result retval;
1158 Return<void> ret = mStream->getCapturePosition(
1159 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
1160 retval = r;
1161 if (retval == Result::OK) {
1162 *frames = hidlFrames;
1163 *time = hidlTime;
1164 }
1165 });
1166 return processReturn("getCapturePosition", ret, retval);
1167 }
1168}
1169
Kevin Rocard070e7512018-05-22 09:29:13 -07001170#if MAJOR_VERSION == 2
1171status_t StreamInHalHidl::getActiveMicrophones(
1172 std::vector<media::MicrophoneInfo> *microphones __unused) {
1173 if (mStream == 0) return NO_INIT;
1174 return INVALID_OPERATION;
1175}
1176
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001177status_t StreamInHalHidl::updateSinkMetadata(
1178 const StreamInHalInterface::SinkMetadata& /* sinkMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -07001179 // Audio HAL V2.0 does not support propagating sink metadata
1180 return INVALID_OPERATION;
1181}
1182
Kevin Rocard3d48dce2018-11-08 17:16:57 -08001183#elif MAJOR_VERSION >= 4
jiabin9ff780e2018-03-19 18:19:52 -07001184status_t StreamInHalHidl::getActiveMicrophones(
1185 std::vector<media::MicrophoneInfo> *microphonesInfo) {
Andy Hung224f82f2022-03-22 00:00:49 -07001186 TIME_CHECK();
jiabin9ff780e2018-03-19 18:19:52 -07001187 if (!mStream) return NO_INIT;
1188 Result retval;
1189 Return<void> ret = mStream->getActiveMicrophones(
1190 [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
1191 retval = r;
1192 for (size_t k = 0; k < micArrayHal.size(); k++) {
1193 audio_microphone_characteristic_t dst;
1194 // convert
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001195 (void)CoreUtils::microphoneInfoToHal(micArrayHal[k], &dst);
jiabin9ff780e2018-03-19 18:19:52 -07001196 media::MicrophoneInfo microphone = media::MicrophoneInfo(dst);
1197 microphonesInfo->push_back(microphone);
1198 }
1199 });
1200 return processReturn("getActiveMicrophones", ret, retval);
1201}
1202
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001203status_t StreamInHalHidl::updateSinkMetadata(const
1204 StreamInHalInterface::SinkMetadata& sinkMetadata) {
Andy Hung224f82f2022-03-22 00:00:49 -07001205 TIME_CHECK();
Mikhail Naganov6718c392022-01-27 22:17:21 +00001206#if MAJOR_VERSION == 4
1207 ::android::hardware::audio::CORE_TYPES_CPP_VERSION::SinkMetadata hidlMetadata;
1208#else
1209 ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::SinkMetadata hidlMetadata;
1210#endif
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001211 if (status_t status = CoreUtils::sinkMetadataFromHalV7(
1212 sinkMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
1213 status != OK) {
1214 return status;
1215 }
1216 return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -07001217}
Kevin Rocard070e7512018-05-22 09:29:13 -07001218#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -07001219
Paul McLean03a6e6a2018-12-04 10:54:13 -07001220#if MAJOR_VERSION < 5
Paul McLean12340082019-03-19 09:35:05 -06001221status_t StreamInHalHidl::setPreferredMicrophoneDirection(
1222 audio_microphone_direction_t direction __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001223 if (mStream == 0) return NO_INIT;
1224 return INVALID_OPERATION;
1225}
1226
Paul McLean12340082019-03-19 09:35:05 -06001227status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001228 if (mStream == 0) return NO_INIT;
1229 return INVALID_OPERATION;
1230}
1231#else
Paul McLean12340082019-03-19 09:35:05 -06001232status_t StreamInHalHidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
Andy Hung224f82f2022-03-22 00:00:49 -07001233 TIME_CHECK();
Paul McLean03a6e6a2018-12-04 10:54:13 -07001234 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001235 return processReturn("setPreferredMicrophoneDirection",
1236 mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction)));
Paul McLean03a6e6a2018-12-04 10:54:13 -07001237}
1238
Paul McLean12340082019-03-19 09:35:05 -06001239status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom) {
Andy Hung224f82f2022-03-22 00:00:49 -07001240 TIME_CHECK();
Paul McLean03a6e6a2018-12-04 10:54:13 -07001241 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001242 return processReturn("setPreferredMicrophoneFieldDimension",
Paul McLean03a6e6a2018-12-04 10:54:13 -07001243 mStream->setMicrophoneFieldDimension(zoom));
1244}
1245#endif
1246
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001247} // namespace android