blob: e162a68e91a1b02a7f67681e73b852d5dde4bf36 [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>
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080023#include <mediautils/SchedulingPolicyService.h>
24#include <utils/Log.h>
25
Mikhail Naganov6718c392022-01-27 22:17:21 +000026#include PATH(android/hardware/audio/CORE_TYPES_FILE_VERSION/IStreamOutCallback.h)
Mikhail Naganov247b5f92021-01-15 19:16:12 +000027#include <HidlUtils.h>
28#include <util/CoreUtils.h>
29
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080030#include "DeviceHalHidl.h"
Mikhail Naganov247b5f92021-01-15 19:16:12 +000031#include "ParameterUtils.h"
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080032#include "StreamHalHidl.h"
33
Mikhail Naganov6718c392022-01-27 22:17:21 +000034using ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::implementation::HidlUtils;
35using ::android::hardware::audio::CORE_TYPES_CPP_VERSION::implementation::CoreUtils;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080036using ::android::hardware::MQDescriptorSync;
37using ::android::hardware::Return;
38using ::android::hardware::Void;
Kevin Rocarddf9b4202018-05-10 19:56:08 -070039
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080040namespace android {
41
Mikhail Naganov9ccaa162018-12-12 10:27:29 -080042using ReadCommand = ::android::hardware::audio::CPP_VERSION::IStreamIn::ReadCommand;
43
Mikhail Naganov6718c392022-01-27 22:17:21 +000044using namespace ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION;
45using namespace ::android::hardware::audio::CORE_TYPES_CPP_VERSION;
Mikhail Naganov9ccaa162018-12-12 10:27:29 -080046
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080047StreamHalHidl::StreamHalHidl(IStream *stream)
48 : ConversionHelperHidl("Stream"),
49 mStream(stream),
50 mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT),
51 mCachedBufferSize(0){
52
53 // Instrument audio signal power logging.
54 // Note: This assumes channel mask, format, and sample rate do not change after creation.
Mikhail Naganov247b5f92021-01-15 19:16:12 +000055 audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
56 if (/* mStreamPowerLog.isUserDebugOrEngBuild() && */
Mikhail Naganov560637e2021-03-31 22:40:13 +000057 StreamHalHidl::getAudioProperties(&config) == NO_ERROR) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +000058 mStreamPowerLog.init(config.sample_rate, config.channel_mask, config.format);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080059 }
60}
61
Andy Hungacb5b982021-01-20 10:12:00 -080062StreamHalHidl::~StreamHalHidl() {
63 // The last step is to flush all binder commands so that the deletion
64 // of IStreamIn / IStreamOut (mStream) is issued with less delay. See b/35394629.
65 hardware::IPCThreadState::self()->flushCommands();
66}
67
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080068status_t StreamHalHidl::getBufferSize(size_t *size) {
69 if (!mStream) return NO_INIT;
70 status_t status = processReturn("getBufferSize", mStream->getBufferSize(), size);
71 if (status == OK) {
72 mCachedBufferSize = *size;
73 }
74 return status;
75}
76
Mikhail Naganov560637e2021-03-31 22:40:13 +000077status_t StreamHalHidl::getAudioProperties(audio_config_base_t *configBase) {
78 *configBase = AUDIO_CONFIG_BASE_INITIALIZER;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080079 if (!mStream) return NO_INIT;
Mikhail Naganov247b5f92021-01-15 19:16:12 +000080#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080081 Return<void> ret = mStream->getAudioProperties(
Kevin Rocardb9cfbf12018-02-23 19:11:06 -080082 [&](uint32_t sr, auto m, auto f) {
Mikhail Naganov560637e2021-03-31 22:40:13 +000083 configBase->sample_rate = sr;
84 configBase->channel_mask = static_cast<audio_channel_mask_t>(m);
85 configBase->format = static_cast<audio_format_t>(f);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080086 });
87 return processReturn("getAudioProperties", ret);
Mikhail Naganov247b5f92021-01-15 19:16:12 +000088#else
89 Result retval;
90 status_t conversionStatus = BAD_VALUE;
Mikhail Naganov247b5f92021-01-15 19:16:12 +000091 Return<void> ret = mStream->getAudioProperties(
92 [&](Result r, const AudioConfigBase& config) {
93 retval = r;
94 if (retval == Result::OK) {
Mikhail Naganov560637e2021-03-31 22:40:13 +000095 conversionStatus = HidlUtils::audioConfigBaseToHal(config, configBase);
Mikhail Naganov247b5f92021-01-15 19:16:12 +000096 }
97 });
98 if (status_t status = processReturn("getAudioProperties", ret, retval); status == NO_ERROR) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +000099 return conversionStatus;
100 } else {
101 return status;
102 }
103#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800104}
105
106status_t StreamHalHidl::setParameters(const String8& kvPairs) {
107 if (!mStream) return NO_INIT;
108 hidl_vec<ParameterValue> hidlParams;
109 status_t status = parametersFromHal(kvPairs, &hidlParams);
110 if (status != OK) return status;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800111 return processReturn("setParameters",
Dean Wheatley7b417a22019-01-31 20:39:42 +1100112 utils::setParameters(mStream, {} /* context */, hidlParams));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800113}
114
115status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
116 values->clear();
117 if (!mStream) return NO_INIT;
118 hidl_vec<hidl_string> hidlKeys;
119 status_t status = keysFromHal(keys, &hidlKeys);
120 if (status != OK) return status;
121 Result retval;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800122 Return<void> ret = utils::getParameters(
123 mStream,
124 {} /* context */,
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800125 hidlKeys,
126 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
127 retval = r;
128 if (retval == Result::OK) {
129 parametersToHal(parameters, values);
130 }
131 });
132 return processReturn("getParameters", ret, retval);
133}
134
135status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
136 if (!mStream) return NO_INIT;
Mikhail Naganov6718c392022-01-27 22:17:21 +0000137 return processReturn("addEffect", mStream->addEffect(effect->effectId()));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800138}
139
140status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
141 if (!mStream) return NO_INIT;
Mikhail Naganov6718c392022-01-27 22:17:21 +0000142 return processReturn("removeEffect", mStream->removeEffect(effect->effectId()));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800143}
144
145status_t StreamHalHidl::standby() {
146 if (!mStream) return NO_INIT;
147 return processReturn("standby", mStream->standby());
148}
149
Andy Hung61589a42021-06-16 09:37:53 -0700150status_t StreamHalHidl::dump(int fd, const Vector<String16>& args) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800151 if (!mStream) return NO_INIT;
152 native_handle_t* hidlHandle = native_handle_create(1, 0);
153 hidlHandle->data[0] = fd;
Andy Hung61589a42021-06-16 09:37:53 -0700154 hidl_vec<hidl_string> hidlArgs;
155 argsFromHal(args, &hidlArgs);
156 Return<void> ret = mStream->debug(hidlHandle, hidlArgs);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800157 native_handle_delete(hidlHandle);
Andy Hunge72ff022021-08-16 10:16:15 -0700158
159 // TODO(b/111997867, b/177271958) Workaround - remove when fixed.
160 // A Binder transmitted fd may not close immediately due to a race condition b/111997867
161 // when the remote binder thread removes the last refcount to the fd blocks in the
162 // kernel for binder activity. We send a Binder ping() command to unblock the thread
163 // and complete the fd close / release.
164 //
165 // See DeviceHalHidl::dump(), EffectHalHidl::dump(), StreamHalHidl::dump(),
166 // EffectsFactoryHalHidl::dumpEffects().
167
168 (void)mStream->ping(); // synchronous Binder call
169
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800170 mStreamPowerLog.dump(fd);
171 return processReturn("dump", ret);
172}
173
174status_t StreamHalHidl::start() {
175 if (!mStream) return NO_INIT;
176 return processReturn("start", mStream->start());
177}
178
179status_t StreamHalHidl::stop() {
180 if (!mStream) return NO_INIT;
181 return processReturn("stop", mStream->stop());
182}
183
184status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
185 struct audio_mmap_buffer_info *info) {
186 Result retval;
187 Return<void> ret = mStream->createMmapBuffer(
188 minSizeFrames,
189 [&](Result r, const MmapBufferInfo& hidlInfo) {
190 retval = r;
191 if (retval == Result::OK) {
192 const native_handle *handle = hidlInfo.sharedMemory.handle();
193 if (handle->numFds > 0) {
194 info->shared_memory_fd = handle->data[0];
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800195#if MAJOR_VERSION >= 4
Kevin Rocard734334f2018-07-12 19:37:41 -0700196 info->flags = audio_mmap_buffer_flag(hidlInfo.flags);
197#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800198 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
Kevin Rocard734334f2018-07-12 19:37:41 -0700199 // Negative buffer size frame was a hack in O and P to
200 // indicate that the buffer is shareable to applications
201 if (info->buffer_size_frames < 0) {
202 info->buffer_size_frames *= -1;
203 info->flags = audio_mmap_buffer_flag(
204 info->flags | AUDIO_MMAP_APPLICATION_SHAREABLE);
205 }
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800206 info->burst_size_frames = hidlInfo.burstSizeFrames;
207 // info->shared_memory_address is not needed in HIDL context
208 info->shared_memory_address = NULL;
209 } else {
210 retval = Result::NOT_INITIALIZED;
211 }
212 }
213 });
214 return processReturn("createMmapBuffer", ret, retval);
215}
216
217status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
218 Result retval;
219 Return<void> ret = mStream->getMmapPosition(
220 [&](Result r, const MmapPosition& hidlPosition) {
221 retval = r;
222 if (retval == Result::OK) {
223 position->time_nanoseconds = hidlPosition.timeNanoseconds;
224 position->position_frames = hidlPosition.positionFrames;
225 }
226 });
227 return processReturn("getMmapPosition", ret, retval);
228}
229
230status_t StreamHalHidl::setHalThreadPriority(int priority) {
231 mHalThreadPriority = priority;
232 return OK;
233}
234
235status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
236 if (mCachedBufferSize != 0) {
237 *size = mCachedBufferSize;
238 return OK;
239 }
240 return getBufferSize(size);
241}
242
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000243status_t StreamHalHidl::getHalPid(pid_t *pid) {
244 using ::android::hidl::base::V1_0::DebugInfo;
245 using ::android::hidl::manager::V1_0::IServiceManager;
246
247 DebugInfo debugInfo;
248 auto ret = mStream->getDebugInfo([&] (const auto &info) {
249 debugInfo = info;
250 });
251 if (!ret.isOk()) {
252 return INVALID_OPERATION;
253 }
254 if (debugInfo.pid != (int)IServiceManager::PidConstant::NO_PID) {
255 *pid = debugInfo.pid;
256 return NO_ERROR;
257 }
258 return NAME_NOT_FOUND;
259}
260
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800261bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
262 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
263 return true;
264 }
265 int err = requestPriority(
266 threadPid, threadId,
267 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
268 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
269 mHalThreadPriority, threadPid, threadId, err);
270 // Audio will still work, but latency will be higher and sometimes unacceptable.
271 return err == 0;
272}
273
Ytai Ben-Tsvif997ffe2022-02-03 16:38:16 -0800274status_t StreamHalHidl::legacyCreateAudioPatch(const struct audio_port_config& port,
275 std::optional<audio_source_t> source,
276 audio_devices_t type) {
277 LOG_ALWAYS_FATAL_IF(port.type != AUDIO_PORT_TYPE_DEVICE, "port type must be device");
278 char* address;
279 if (strcmp(port.ext.device.address, "") != 0) {
280 // FIXME: we only support address on first sink with HAL version < 3.0
281 address = audio_device_address_to_parameter(port.ext.device.type, port.ext.device.address);
282 } else {
283 address = (char*)calloc(1, 1);
284 }
285 AudioParameter param = AudioParameter(String8(address));
286 free(address);
287 param.addInt(String8(AudioParameter::keyRouting), (int)type);
288 if (source.has_value()) {
289 param.addInt(String8(AudioParameter::keyInputSource), (int)source.value());
290 }
291 return setParameters(param.toString());
292}
293
294status_t StreamHalHidl::legacyReleaseAudioPatch() {
295 AudioParameter param;
296 param.addInt(String8(AudioParameter::keyRouting), 0);
297 return setParameters(param.toString());
298}
299
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800300namespace {
301
302/* Notes on callback ownership.
303
304This is how (Hw)Binder ownership model looks like. The server implementation
305is owned by Binder framework (via sp<>). Proxies are owned by clients.
306When the last proxy disappears, Binder framework releases the server impl.
307
308Thus, it is not needed to keep any references to StreamOutCallback (this is
309the server impl) -- it will live as long as HAL server holds a strong ref to
310IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
311from the destructor of StreamOutHalHidl.
312
313The callback only keeps a weak reference to the stream. The stream is owned
314by AudioFlinger.
315
316*/
317
318struct StreamOutCallback : public IStreamOutCallback {
319 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
320
321 // IStreamOutCallback implementation
322 Return<void> onWriteReady() override {
323 sp<StreamOutHalHidl> stream = mStream.promote();
324 if (stream != 0) {
325 stream->onWriteReady();
326 }
327 return Void();
328 }
329
330 Return<void> onDrainReady() override {
331 sp<StreamOutHalHidl> stream = mStream.promote();
332 if (stream != 0) {
333 stream->onDrainReady();
334 }
335 return Void();
336 }
337
338 Return<void> onError() override {
339 sp<StreamOutHalHidl> stream = mStream.promote();
340 if (stream != 0) {
341 stream->onError();
342 }
343 return Void();
344 }
345
346 private:
Andy Hung638f45b2021-01-18 20:02:56 -0800347 const wp<StreamOutHalHidl> mStream;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800348};
349
350} // namespace
351
Mikhail Naganov6718c392022-01-27 22:17:21 +0000352StreamOutHalHidl::StreamOutHalHidl(
353 const sp<::android::hardware::audio::CPP_VERSION::IStreamOut>& stream)
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800354 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
355}
356
357StreamOutHalHidl::~StreamOutHalHidl() {
358 if (mStream != 0) {
Andy Hung638f45b2021-01-18 20:02:56 -0800359 if (mCallback.load().unsafe_get()) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800360 processReturn("clearCallback", mStream->clearCallback());
361 }
jiabinf6eb4c32020-02-25 14:06:25 -0800362#if MAJOR_VERSION >= 6
Andy Hung638f45b2021-01-18 20:02:56 -0800363 if (mEventCallback.load().unsafe_get() != nullptr) {
jiabinf6eb4c32020-02-25 14:06:25 -0800364 processReturn("setEventCallback",
365 mStream->setEventCallback(nullptr));
366 }
367#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800368 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800369 }
Andy Hung638f45b2021-01-18 20:02:56 -0800370 mCallback = nullptr;
371 mEventCallback = nullptr;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800372 if (mEfGroup) {
373 EventFlag::deleteEventFlag(&mEfGroup);
374 }
375}
376
377status_t StreamOutHalHidl::getFrameSize(size_t *size) {
378 if (mStream == 0) return NO_INIT;
379 return processReturn("getFrameSize", mStream->getFrameSize(), size);
380}
381
382status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
383 if (mStream == 0) return NO_INIT;
384 if (mWriterClient == gettid() && mCommandMQ) {
385 return callWriterThread(
386 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
387 [&](const WriteStatus& writeStatus) {
388 *latency = writeStatus.reply.latencyMs;
389 });
390 } else {
391 return processReturn("getLatency", mStream->getLatency(), latency);
392 }
393}
394
395status_t StreamOutHalHidl::setVolume(float left, float right) {
396 if (mStream == 0) return NO_INIT;
397 return processReturn("setVolume", mStream->setVolume(left, right));
398}
399
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800400#if MAJOR_VERSION == 2
401status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
402 if (mStream == 0) return NO_INIT;
403 std::vector<ParameterValue> parameters;
404 String8 halParameters;
405 parameters.push_back({AudioParameter::keyPresentationId, std::to_string(presentationId)});
406 parameters.push_back({AudioParameter::keyProgramId, std::to_string(programId)});
407 parametersToHal(hidl_vec<ParameterValue>(parameters), &halParameters);
408 return setParameters(halParameters);
409}
Kevin Rocard1cf6b4d2018-11-20 18:05:44 -0800410#elif MAJOR_VERSION >= 4
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800411status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
412 if (mStream == 0) return NO_INIT;
413 return processReturn("selectPresentation",
414 mStream->selectPresentation(presentationId, programId));
415}
416#endif
417
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800418status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
419 if (mStream == 0) return NO_INIT;
420 *written = 0;
421
422 if (bytes == 0 && !mDataMQ) {
423 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
Andy Hung638f45b2021-01-18 20:02:56 -0800424 ALOGW_IF(mCallback.load().unsafe_get(), "First call to async write with 0 bytes");
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800425 return OK;
426 }
427
428 status_t status;
429 if (!mDataMQ) {
430 // In case if playback starts close to the end of a compressed track, the bytes
431 // that need to be written is less than the actual buffer size. Need to use
432 // full buffer size for the MQ since otherwise after seeking back to the middle
433 // data will be truncated.
434 size_t bufferSize;
435 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
436 return status;
437 }
438 if (bytes > bufferSize) bufferSize = bytes;
439 if ((status = prepareForWriting(bufferSize)) != OK) {
440 return status;
441 }
442 }
443
444 status = callWriterThread(
445 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
446 [&] (const WriteStatus& writeStatus) {
447 *written = writeStatus.reply.written;
448 // Diagnostics of the cause of b/35813113.
449 ALOGE_IF(*written > bytes,
450 "hal reports more bytes written than asked for: %lld > %lld",
451 (long long)*written, (long long)bytes);
452 });
453 mStreamPowerLog.log(buffer, *written);
454 return status;
455}
456
457status_t StreamOutHalHidl::callWriterThread(
458 WriteCommand cmd, const char* cmdName,
459 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
460 if (!mCommandMQ->write(&cmd)) {
461 ALOGE("command message queue write failed for \"%s\"", cmdName);
462 return -EAGAIN;
463 }
464 if (data != nullptr) {
465 size_t availableToWrite = mDataMQ->availableToWrite();
466 if (dataSize > availableToWrite) {
467 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
468 (long long)dataSize, (long long)availableToWrite);
469 dataSize = availableToWrite;
470 }
471 if (!mDataMQ->write(data, dataSize)) {
472 ALOGE("data message queue write failed for \"%s\"", cmdName);
473 }
474 }
475 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
476
477 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
478 uint32_t efState = 0;
479retry:
480 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
481 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
482 WriteStatus writeStatus;
483 writeStatus.retval = Result::NOT_INITIALIZED;
484 if (!mStatusMQ->read(&writeStatus)) {
485 ALOGE("status message read failed for \"%s\"", cmdName);
486 }
487 if (writeStatus.retval == Result::OK) {
488 ret = OK;
489 callback(writeStatus);
490 } else {
491 ret = processReturn(cmdName, writeStatus.retval);
492 }
493 return ret;
494 }
495 if (ret == -EAGAIN || ret == -EINTR) {
496 // Spurious wakeup. This normally retries no more than once.
497 goto retry;
498 }
499 return ret;
500}
501
502status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
503 std::unique_ptr<CommandMQ> tempCommandMQ;
504 std::unique_ptr<DataMQ> tempDataMQ;
505 std::unique_ptr<StatusMQ> tempStatusMQ;
506 Result retval;
507 pid_t halThreadPid, halThreadTid;
508 Return<void> ret = mStream->prepareForWriting(
509 1, bufferSize,
510 [&](Result r,
511 const CommandMQ::Descriptor& commandMQ,
512 const DataMQ::Descriptor& dataMQ,
513 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000514 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800515 retval = r;
516 if (retval == Result::OK) {
517 tempCommandMQ.reset(new CommandMQ(commandMQ));
518 tempDataMQ.reset(new DataMQ(dataMQ));
519 tempStatusMQ.reset(new StatusMQ(statusMQ));
520 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
521 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
522 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000523#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800524 halThreadPid = halThreadInfo.pid;
525 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000526#else
527 halThreadTid = halThreadInfo;
528#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800529 }
530 });
531 if (!ret.isOk() || retval != Result::OK) {
532 return processReturn("prepareForWriting", ret, retval);
533 }
534 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
535 !tempDataMQ || !tempDataMQ->isValid() ||
536 !tempStatusMQ || !tempStatusMQ->isValid() ||
537 !mEfGroup) {
538 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
539 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
540 "Command message queue for writing is invalid");
541 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
542 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
543 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
544 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
545 "Status message queue for writing is invalid");
546 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
547 return NO_INIT;
548 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000549#if MAJOR_VERSION >= 7
550 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
551 return status;
552 }
553#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800554 requestHalThreadPriority(halThreadPid, halThreadTid);
555
556 mCommandMQ = std::move(tempCommandMQ);
557 mDataMQ = std::move(tempDataMQ);
558 mStatusMQ = std::move(tempStatusMQ);
559 mWriterClient = gettid();
560 return OK;
561}
562
563status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
564 if (mStream == 0) return NO_INIT;
565 Result retval;
566 Return<void> ret = mStream->getRenderPosition(
567 [&](Result r, uint32_t d) {
568 retval = r;
569 if (retval == Result::OK) {
570 *dspFrames = d;
571 }
572 });
573 return processReturn("getRenderPosition", ret, retval);
574}
575
576status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
577 if (mStream == 0) return NO_INIT;
578 Result retval;
579 Return<void> ret = mStream->getNextWriteTimestamp(
580 [&](Result r, int64_t t) {
581 retval = r;
582 if (retval == Result::OK) {
583 *timestamp = t;
584 }
585 });
586 return processReturn("getRenderPosition", ret, retval);
587}
588
589status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
590 if (mStream == 0) return NO_INIT;
591 status_t status = processReturn(
592 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
593 if (status == OK) {
594 mCallback = callback;
595 }
596 return status;
597}
598
599status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
600 if (mStream == 0) return NO_INIT;
601 Return<void> ret = mStream->supportsPauseAndResume(
602 [&](bool p, bool r) {
603 *supportsPause = p;
604 *supportsResume = r;
605 });
606 return processReturn("supportsPauseAndResume", ret);
607}
608
609status_t StreamOutHalHidl::pause() {
610 if (mStream == 0) return NO_INIT;
611 return processReturn("pause", mStream->pause());
612}
613
614status_t StreamOutHalHidl::resume() {
615 if (mStream == 0) return NO_INIT;
616 return processReturn("pause", mStream->resume());
617}
618
619status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
620 if (mStream == 0) return NO_INIT;
621 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
622}
623
624status_t StreamOutHalHidl::drain(bool earlyNotify) {
625 if (mStream == 0) return NO_INIT;
626 return processReturn(
627 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
628}
629
630status_t StreamOutHalHidl::flush() {
631 if (mStream == 0) return NO_INIT;
632 return processReturn("pause", mStream->flush());
633}
634
635status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
636 if (mStream == 0) return NO_INIT;
637 if (mWriterClient == gettid() && mCommandMQ) {
638 return callWriterThread(
639 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
640 [&](const WriteStatus& writeStatus) {
641 *frames = writeStatus.reply.presentationPosition.frames;
642 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
643 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
644 });
645 } else {
646 Result retval;
647 Return<void> ret = mStream->getPresentationPosition(
648 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
649 retval = r;
650 if (retval == Result::OK) {
651 *frames = hidlFrames;
652 timestamp->tv_sec = hidlTimeStamp.tvSec;
653 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
654 }
655 });
656 return processReturn("getPresentationPosition", ret, retval);
657 }
658}
659
Kevin Rocard070e7512018-05-22 09:29:13 -0700660#if MAJOR_VERSION == 2
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800661status_t StreamOutHalHidl::updateSourceMetadata(
662 const StreamOutHalInterface::SourceMetadata& /* sourceMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700663 // Audio HAL V2.0 does not support propagating source metadata
664 return INVALID_OPERATION;
665}
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800666#elif MAJOR_VERSION >= 4
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800667status_t StreamOutHalHidl::updateSourceMetadata(
668 const StreamOutHalInterface::SourceMetadata& sourceMetadata) {
Mikhail Naganov6718c392022-01-27 22:17:21 +0000669#if MAJOR_VERSION == 4
670 ::android::hardware::audio::CORE_TYPES_CPP_VERSION::SourceMetadata hidlMetadata;
671#else
672 ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::SourceMetadata hidlMetadata;
673#endif
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000674 if (status_t status = CoreUtils::sourceMetadataFromHalV7(
675 sourceMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
676 status != OK) {
677 return status;
678 }
679 return processReturn("updateSourceMetadata", mStream->updateSourceMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -0700680}
Kevin Rocard070e7512018-05-22 09:29:13 -0700681#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700682
jiabinf6eb4c32020-02-25 14:06:25 -0800683#if MAJOR_VERSION < 6
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800684status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode __unused) {
685 return INVALID_OPERATION;
686}
687
688status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode __unused) {
689 return INVALID_OPERATION;
690}
691
692status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB __unused) {
693 return INVALID_OPERATION;
694}
695
696status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB __unused) {
697 return INVALID_OPERATION;
698}
699
700status_t StreamOutHalHidl::getPlaybackRateParameters(
701 audio_playback_rate_t* playbackRate __unused) {
702 return INVALID_OPERATION;
703}
704
705status_t StreamOutHalHidl::setPlaybackRateParameters(
706 const audio_playback_rate_t& playbackRate __unused) {
707 return INVALID_OPERATION;
708}
709
jiabinf6eb4c32020-02-25 14:06:25 -0800710status_t StreamOutHalHidl::setEventCallback(
711 const sp<StreamOutHalInterfaceEventCallback>& callback __unused) {
712 // Codec format callback is supported starting from audio HAL V6.0
713 return INVALID_OPERATION;
714}
Eric Laurentafa586b2022-01-27 21:10:55 +0100715
jiabinf6eb4c32020-02-25 14:06:25 -0800716#else
717
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800718status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode) {
719 if (mStream == 0) return NO_INIT;
720 Result retval;
721 Return<void> ret = mStream->getDualMonoMode(
722 [&](Result r, DualMonoMode hidlMode) {
723 retval = r;
724 if (retval == Result::OK) {
725 *mode = static_cast<audio_dual_mono_mode_t>(hidlMode);
726 }
727 });
728 return processReturn("getDualMonoMode", ret, retval);
729}
730
731status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode) {
732 if (mStream == 0) return NO_INIT;
733 return processReturn(
734 "setDualMonoMode", mStream->setDualMonoMode(static_cast<DualMonoMode>(mode)));
735}
736
737status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB) {
738 if (mStream == 0) return NO_INIT;
739 Result retval;
740 Return<void> ret = mStream->getAudioDescriptionMixLevel(
741 [&](Result r, float hidlLeveldB) {
742 retval = r;
743 if (retval == Result::OK) {
744 *leveldB = hidlLeveldB;
745 }
746 });
747 return processReturn("getAudioDescriptionMixLevel", ret, retval);
748}
749
750status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB) {
751 if (mStream == 0) return NO_INIT;
752 return processReturn(
753 "setAudioDescriptionMixLevel", mStream->setAudioDescriptionMixLevel(leveldB));
754}
755
756status_t StreamOutHalHidl::getPlaybackRateParameters(audio_playback_rate_t* playbackRate) {
757 if (mStream == 0) return NO_INIT;
758 Result retval;
759 Return<void> ret = mStream->getPlaybackRateParameters(
760 [&](Result r, PlaybackRate hidlPlaybackRate) {
761 retval = r;
762 if (retval == Result::OK) {
763 playbackRate->mSpeed = hidlPlaybackRate.speed;
764 playbackRate->mPitch = hidlPlaybackRate.pitch;
765 playbackRate->mStretchMode =
766 static_cast<audio_timestretch_stretch_mode_t>(
767 hidlPlaybackRate.timestretchMode);
768 playbackRate->mFallbackMode =
769 static_cast<audio_timestretch_fallback_mode_t>(
770 hidlPlaybackRate.fallbackMode);
771 }
772 });
773 return processReturn("getPlaybackRateParameters", ret, retval);
774}
775
776status_t StreamOutHalHidl::setPlaybackRateParameters(const audio_playback_rate_t& playbackRate) {
777 if (mStream == 0) return NO_INIT;
778 return processReturn(
779 "setPlaybackRateParameters", mStream->setPlaybackRateParameters(
780 PlaybackRate{playbackRate.mSpeed, playbackRate.mPitch,
781 static_cast<TimestretchMode>(playbackRate.mStretchMode),
782 static_cast<TimestretchFallbackMode>(playbackRate.mFallbackMode)}));
783}
784
Mikhail Naganov6718c392022-01-27 22:17:21 +0000785#include PATH(android/hardware/audio/CORE_TYPES_FILE_VERSION/IStreamOutEventCallback.h)
jiabinf6eb4c32020-02-25 14:06:25 -0800786
787namespace {
788
789struct StreamOutEventCallback : public IStreamOutEventCallback {
790 StreamOutEventCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
791
792 // IStreamOutEventCallback implementation
793 Return<void> onCodecFormatChanged(
794 const android::hardware::hidl_vec<uint8_t>& audioMetadata) override {
795 sp<StreamOutHalHidl> stream = mStream.promote();
796 if (stream != nullptr) {
797 std::basic_string<uint8_t> metadataBs(audioMetadata.begin(), audioMetadata.end());
798 stream->onCodecFormatChanged(metadataBs);
799 }
800 return Void();
801 }
802
803 private:
804 wp<StreamOutHalHidl> mStream;
805};
806
807} // namespace
808
809status_t StreamOutHalHidl::setEventCallback(
810 const sp<StreamOutHalInterfaceEventCallback>& callback) {
811 if (mStream == nullptr) return NO_INIT;
812 mEventCallback = callback;
813 status_t status = processReturn(
814 "setEventCallback",
815 mStream->setEventCallback(
816 callback.get() == nullptr ? nullptr : new StreamOutEventCallback(this)));
817 return status;
818}
819#endif
820
Eric Laurentafa586b2022-01-27 21:10:55 +0100821#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
822using hardware::audio::V7_1::LatencyMode;
823
824status_t StreamOutHalHidl::setLatencyMode(audio_latency_mode_t mode) {
825 if (mStream == 0) return NO_INIT;
826 return processReturn(
827 "setLatencyMode", mStream->setLatencyMode(static_cast<LatencyMode>(mode)));
828};
829
830status_t StreamOutHalHidl::getRecommendedLatencyModes(std::vector<audio_latency_mode_t> *modes) {
831 if (!mStream) return NO_INIT;
832 Result retval;
833 Return<void> ret = mStream->getRecommendedLatencyModes(
834 [&](Result r, hidl_vec<LatencyMode> hidlModes) {
835 retval = r;
836 for (size_t i = 0; i < hidlModes.size(); i++) {
837 modes->push_back(static_cast<audio_latency_mode_t>(hidlModes[i]));
838 }
839 });
840 return processReturn("getRecommendedLatencyModes", ret, retval);
841};
842
843#include PATH(android/hardware/audio/FILE_VERSION/IStreamOutLatencyModeCallback.h)
844
845using hardware::audio::V7_1::IStreamOutLatencyModeCallback;
846
847namespace {
848struct StreamOutLatencyModeCallback : public IStreamOutLatencyModeCallback {
849 StreamOutLatencyModeCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
850
851 // IStreamOutLatencyModeCallback implementation
852 Return<void> onRecommendedLatencyModeChanged(const hidl_vec<LatencyMode>& hidlModes) override {
853 sp<StreamOutHalHidl> stream = mStream.promote();
854 if (stream != nullptr) {
855 std::vector<audio_latency_mode_t> modes;
856 for (size_t i = 0; i < hidlModes.size(); i++) {
857 modes.push_back(static_cast<audio_latency_mode_t>(hidlModes[i]));
858 }
859 stream->onRecommendedLatencyModeChanged(modes);
860 }
861 return Void();
862 }
863
864 private:
865 wp<StreamOutHalHidl> mStream;
866};
867} // namespace
868
869status_t StreamOutHalHidl::setLatencyModeCallback(
870 const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) {
871
872 if (mStream == nullptr) return NO_INIT;
873 mLatencyModeCallback = callback;
874 status_t status = processReturn(
875 "setLatencyModeCallback",
876 mStream->setLatencyModeCallback(
877 callback.get() == nullptr ? nullptr : new StreamOutLatencyModeCallback(this)));
878 return status;
879};
880
881#else
882
883status_t StreamOutHalHidl::setLatencyMode(audio_latency_mode_t mode __unused) {
884 return INVALID_OPERATION;
885};
886
887status_t StreamOutHalHidl::getRecommendedLatencyModes(
888 std::vector<audio_latency_mode_t> *modes __unused) {
889 return INVALID_OPERATION;
890};
891
892status_t StreamOutHalHidl::setLatencyModeCallback(
893 const sp<StreamOutHalInterfaceLatencyModeCallback>& callback __unused) {
894 return INVALID_OPERATION;
895};
896
897#endif
898
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800899void StreamOutHalHidl::onWriteReady() {
Andy Hung638f45b2021-01-18 20:02:56 -0800900 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800901 if (callback == 0) return;
902 ALOGV("asyncCallback onWriteReady");
903 callback->onWriteReady();
904}
905
906void StreamOutHalHidl::onDrainReady() {
Andy Hung638f45b2021-01-18 20:02:56 -0800907 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800908 if (callback == 0) return;
909 ALOGV("asyncCallback onDrainReady");
910 callback->onDrainReady();
911}
912
913void StreamOutHalHidl::onError() {
Andy Hung638f45b2021-01-18 20:02:56 -0800914 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800915 if (callback == 0) return;
916 ALOGV("asyncCallback onError");
917 callback->onError();
918}
919
jiabinf6eb4c32020-02-25 14:06:25 -0800920void StreamOutHalHidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) {
Andy Hung638f45b2021-01-18 20:02:56 -0800921 sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.load().promote();
jiabinf6eb4c32020-02-25 14:06:25 -0800922 if (callback == nullptr) return;
923 ALOGV("asyncCodecFormatCallback %s", __func__);
924 callback->onCodecFormatChanged(metadataBs);
925}
926
Eric Laurentafa586b2022-01-27 21:10:55 +0100927void StreamOutHalHidl::onRecommendedLatencyModeChanged(
928 const std::vector<audio_latency_mode_t>& modes) {
929 sp<StreamOutHalInterfaceLatencyModeCallback> callback = mLatencyModeCallback.load().promote();
930 if (callback == nullptr) return;
931 callback->onRecommendedLatencyModeChanged(modes);
932}
933
Ytai Ben-Tsvi7e0183f2022-02-04 10:49:54 -0800934status_t StreamOutHalHidl::exit() {
935 // FIXME this is using hard-coded strings but in the future, this functionality will be
936 // converted to use audio HAL extensions required to support tunneling
937 return setParameters(String8("exiting=1"));
938}
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800939
Mikhail Naganov6718c392022-01-27 22:17:21 +0000940StreamInHalHidl::StreamInHalHidl(
941 const sp<::android::hardware::audio::CPP_VERSION::IStreamIn>& stream)
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800942 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
943}
944
945StreamInHalHidl::~StreamInHalHidl() {
946 if (mStream != 0) {
947 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800948 }
949 if (mEfGroup) {
950 EventFlag::deleteEventFlag(&mEfGroup);
951 }
952}
953
954status_t StreamInHalHidl::getFrameSize(size_t *size) {
955 if (mStream == 0) return NO_INIT;
956 return processReturn("getFrameSize", mStream->getFrameSize(), size);
957}
958
959status_t StreamInHalHidl::setGain(float gain) {
960 if (mStream == 0) return NO_INIT;
961 return processReturn("setGain", mStream->setGain(gain));
962}
963
964status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
965 if (mStream == 0) return NO_INIT;
966 *read = 0;
967
968 if (bytes == 0 && !mDataMQ) {
969 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
970 return OK;
971 }
972
973 status_t status;
974 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
975 return status;
976 }
977
978 ReadParameters params;
979 params.command = ReadCommand::READ;
980 params.params.read = bytes;
981 status = callReaderThread(params, "read",
982 [&](const ReadStatus& readStatus) {
983 const size_t availToRead = mDataMQ->availableToRead();
984 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
985 ALOGE("data message queue read failed for \"read\"");
986 }
987 ALOGW_IF(availToRead != readStatus.reply.read,
988 "HAL read report inconsistent: mq = %d, status = %d",
989 (int32_t)availToRead, (int32_t)readStatus.reply.read);
990 *read = readStatus.reply.read;
991 });
992 mStreamPowerLog.log(buffer, *read);
993 return status;
994}
995
996status_t StreamInHalHidl::callReaderThread(
997 const ReadParameters& params, const char* cmdName,
998 StreamInHalHidl::ReaderCallback callback) {
999 if (!mCommandMQ->write(&params)) {
1000 ALOGW("command message queue write failed");
1001 return -EAGAIN;
1002 }
1003 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
1004
1005 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
1006 uint32_t efState = 0;
1007retry:
1008 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
1009 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
1010 ReadStatus readStatus;
1011 readStatus.retval = Result::NOT_INITIALIZED;
1012 if (!mStatusMQ->read(&readStatus)) {
1013 ALOGE("status message read failed for \"%s\"", cmdName);
1014 }
1015 if (readStatus.retval == Result::OK) {
1016 ret = OK;
1017 callback(readStatus);
1018 } else {
1019 ret = processReturn(cmdName, readStatus.retval);
1020 }
1021 return ret;
1022 }
1023 if (ret == -EAGAIN || ret == -EINTR) {
1024 // Spurious wakeup. This normally retries no more than once.
1025 goto retry;
1026 }
1027 return ret;
1028}
1029
1030status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
1031 std::unique_ptr<CommandMQ> tempCommandMQ;
1032 std::unique_ptr<DataMQ> tempDataMQ;
1033 std::unique_ptr<StatusMQ> tempStatusMQ;
1034 Result retval;
1035 pid_t halThreadPid, halThreadTid;
1036 Return<void> ret = mStream->prepareForReading(
1037 1, bufferSize,
1038 [&](Result r,
1039 const CommandMQ::Descriptor& commandMQ,
1040 const DataMQ::Descriptor& dataMQ,
1041 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001042 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001043 retval = r;
1044 if (retval == Result::OK) {
1045 tempCommandMQ.reset(new CommandMQ(commandMQ));
1046 tempDataMQ.reset(new DataMQ(dataMQ));
1047 tempStatusMQ.reset(new StatusMQ(statusMQ));
1048 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
1049 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
1050 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001051#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001052 halThreadPid = halThreadInfo.pid;
1053 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001054#else
1055 halThreadTid = halThreadInfo;
1056#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001057 }
1058 });
1059 if (!ret.isOk() || retval != Result::OK) {
1060 return processReturn("prepareForReading", ret, retval);
1061 }
1062 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
1063 !tempDataMQ || !tempDataMQ->isValid() ||
1064 !tempStatusMQ || !tempStatusMQ->isValid() ||
1065 !mEfGroup) {
1066 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
1067 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
1068 "Command message queue for writing is invalid");
1069 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
1070 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
1071 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
1072 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
1073 "Status message queue for reading is invalid");
1074 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
1075 return NO_INIT;
1076 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001077#if MAJOR_VERSION >= 7
1078 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
1079 return status;
1080 }
1081#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001082 requestHalThreadPriority(halThreadPid, halThreadTid);
1083
1084 mCommandMQ = std::move(tempCommandMQ);
1085 mDataMQ = std::move(tempDataMQ);
1086 mStatusMQ = std::move(tempStatusMQ);
1087 mReaderClient = gettid();
1088 return OK;
1089}
1090
1091status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
1092 if (mStream == 0) return NO_INIT;
1093 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
1094}
1095
1096status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
1097 if (mStream == 0) return NO_INIT;
1098 if (mReaderClient == gettid() && mCommandMQ) {
1099 ReadParameters params;
1100 params.command = ReadCommand::GET_CAPTURE_POSITION;
1101 return callReaderThread(params, "getCapturePosition",
1102 [&](const ReadStatus& readStatus) {
1103 *frames = readStatus.reply.capturePosition.frames;
1104 *time = readStatus.reply.capturePosition.time;
1105 });
1106 } else {
1107 Result retval;
1108 Return<void> ret = mStream->getCapturePosition(
1109 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
1110 retval = r;
1111 if (retval == Result::OK) {
1112 *frames = hidlFrames;
1113 *time = hidlTime;
1114 }
1115 });
1116 return processReturn("getCapturePosition", ret, retval);
1117 }
1118}
1119
Kevin Rocard070e7512018-05-22 09:29:13 -07001120#if MAJOR_VERSION == 2
1121status_t StreamInHalHidl::getActiveMicrophones(
1122 std::vector<media::MicrophoneInfo> *microphones __unused) {
1123 if (mStream == 0) return NO_INIT;
1124 return INVALID_OPERATION;
1125}
1126
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001127status_t StreamInHalHidl::updateSinkMetadata(
1128 const StreamInHalInterface::SinkMetadata& /* sinkMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -07001129 // Audio HAL V2.0 does not support propagating sink metadata
1130 return INVALID_OPERATION;
1131}
1132
Kevin Rocard3d48dce2018-11-08 17:16:57 -08001133#elif MAJOR_VERSION >= 4
jiabin9ff780e2018-03-19 18:19:52 -07001134status_t StreamInHalHidl::getActiveMicrophones(
1135 std::vector<media::MicrophoneInfo> *microphonesInfo) {
1136 if (!mStream) return NO_INIT;
1137 Result retval;
1138 Return<void> ret = mStream->getActiveMicrophones(
1139 [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
1140 retval = r;
1141 for (size_t k = 0; k < micArrayHal.size(); k++) {
1142 audio_microphone_characteristic_t dst;
1143 // convert
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001144 (void)CoreUtils::microphoneInfoToHal(micArrayHal[k], &dst);
jiabin9ff780e2018-03-19 18:19:52 -07001145 media::MicrophoneInfo microphone = media::MicrophoneInfo(dst);
1146 microphonesInfo->push_back(microphone);
1147 }
1148 });
1149 return processReturn("getActiveMicrophones", ret, retval);
1150}
1151
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001152status_t StreamInHalHidl::updateSinkMetadata(const
1153 StreamInHalInterface::SinkMetadata& sinkMetadata) {
Mikhail Naganov6718c392022-01-27 22:17:21 +00001154#if MAJOR_VERSION == 4
1155 ::android::hardware::audio::CORE_TYPES_CPP_VERSION::SinkMetadata hidlMetadata;
1156#else
1157 ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::SinkMetadata hidlMetadata;
1158#endif
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001159 if (status_t status = CoreUtils::sinkMetadataFromHalV7(
1160 sinkMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
1161 status != OK) {
1162 return status;
1163 }
1164 return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -07001165}
Kevin Rocard070e7512018-05-22 09:29:13 -07001166#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -07001167
Paul McLean03a6e6a2018-12-04 10:54:13 -07001168#if MAJOR_VERSION < 5
Paul McLean12340082019-03-19 09:35:05 -06001169status_t StreamInHalHidl::setPreferredMicrophoneDirection(
1170 audio_microphone_direction_t direction __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001171 if (mStream == 0) return NO_INIT;
1172 return INVALID_OPERATION;
1173}
1174
Paul McLean12340082019-03-19 09:35:05 -06001175status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001176 if (mStream == 0) return NO_INIT;
1177 return INVALID_OPERATION;
1178}
1179#else
Paul McLean12340082019-03-19 09:35:05 -06001180status_t StreamInHalHidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001181 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001182 return processReturn("setPreferredMicrophoneDirection",
1183 mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction)));
Paul McLean03a6e6a2018-12-04 10:54:13 -07001184}
1185
Paul McLean12340082019-03-19 09:35:05 -06001186status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001187 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001188 return processReturn("setPreferredMicrophoneFieldDimension",
Paul McLean03a6e6a2018-12-04 10:54:13 -07001189 mStream->setMicrophoneFieldDimension(zoom));
1190}
1191#endif
1192
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001193} // namespace android