blob: 539a1496a732f3cb452fcc5ab297fff8c93c8d8a [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 Naganov247b5f92021-01-15 19:16:12 +000026#include PATH(android/hardware/audio/FILE_VERSION/IStreamOutCallback.h)
27#include <HidlUtils.h>
28#include <util/CoreUtils.h>
29
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080030#include "DeviceHalHidl.h"
31#include "EffectHalHidl.h"
Mikhail Naganov247b5f92021-01-15 19:16:12 +000032#include "ParameterUtils.h"
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080033#include "StreamHalHidl.h"
34
Mikhail Naganov247b5f92021-01-15 19:16:12 +000035using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils;
36using ::android::hardware::audio::CPP_VERSION::implementation::CoreUtils;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080037using ::android::hardware::MQDescriptorSync;
38using ::android::hardware::Return;
39using ::android::hardware::Void;
Kevin Rocarddf9b4202018-05-10 19:56:08 -070040
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080041namespace android {
Kevin Rocard070e7512018-05-22 09:29:13 -070042namespace CPP_VERSION {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080043
Mikhail Naganov595caa32018-12-13 11:08:28 -080044using EffectHalHidl = ::android::effect::CPP_VERSION::EffectHalHidl;
Mikhail Naganov9ccaa162018-12-12 10:27:29 -080045using ReadCommand = ::android::hardware::audio::CPP_VERSION::IStreamIn::ReadCommand;
46
47using namespace ::android::hardware::audio::common::CPP_VERSION;
48using namespace ::android::hardware::audio::CPP_VERSION;
49
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080050StreamHalHidl::StreamHalHidl(IStream *stream)
51 : ConversionHelperHidl("Stream"),
52 mStream(stream),
53 mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT),
54 mCachedBufferSize(0){
55
56 // Instrument audio signal power logging.
57 // Note: This assumes channel mask, format, and sample rate do not change after creation.
Mikhail Naganov247b5f92021-01-15 19:16:12 +000058 audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
59 if (/* mStreamPowerLog.isUserDebugOrEngBuild() && */
Mikhail Naganov560637e2021-03-31 22:40:13 +000060 StreamHalHidl::getAudioProperties(&config) == NO_ERROR) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +000061 mStreamPowerLog.init(config.sample_rate, config.channel_mask, config.format);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080062 }
63}
64
Andy Hungacb5b982021-01-20 10:12:00 -080065StreamHalHidl::~StreamHalHidl() {
66 // The last step is to flush all binder commands so that the deletion
67 // of IStreamIn / IStreamOut (mStream) is issued with less delay. See b/35394629.
68 hardware::IPCThreadState::self()->flushCommands();
69}
70
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080071status_t StreamHalHidl::getBufferSize(size_t *size) {
72 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) {
81 *configBase = AUDIO_CONFIG_BASE_INITIALIZER;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080082 if (!mStream) return NO_INIT;
Mikhail Naganov247b5f92021-01-15 19:16:12 +000083#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080084 Return<void> ret = mStream->getAudioProperties(
Kevin Rocardb9cfbf12018-02-23 19:11:06 -080085 [&](uint32_t sr, auto m, auto f) {
Mikhail Naganov560637e2021-03-31 22:40:13 +000086 configBase->sample_rate = sr;
87 configBase->channel_mask = static_cast<audio_channel_mask_t>(m);
88 configBase->format = static_cast<audio_format_t>(f);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080089 });
90 return processReturn("getAudioProperties", ret);
Mikhail Naganov247b5f92021-01-15 19:16:12 +000091#else
92 Result retval;
93 status_t conversionStatus = BAD_VALUE;
Mikhail Naganov247b5f92021-01-15 19:16:12 +000094 Return<void> ret = mStream->getAudioProperties(
95 [&](Result r, const AudioConfigBase& config) {
96 retval = r;
97 if (retval == Result::OK) {
Mikhail Naganov560637e2021-03-31 22:40:13 +000098 conversionStatus = HidlUtils::audioConfigBaseToHal(config, configBase);
Mikhail Naganov247b5f92021-01-15 19:16:12 +000099 }
100 });
101 if (status_t status = processReturn("getAudioProperties", ret, retval); status == NO_ERROR) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000102 return conversionStatus;
103 } else {
104 return status;
105 }
106#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800107}
108
109status_t StreamHalHidl::setParameters(const String8& kvPairs) {
110 if (!mStream) return NO_INIT;
111 hidl_vec<ParameterValue> hidlParams;
112 status_t status = parametersFromHal(kvPairs, &hidlParams);
113 if (status != OK) return status;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800114 return processReturn("setParameters",
Dean Wheatley7b417a22019-01-31 20:39:42 +1100115 utils::setParameters(mStream, {} /* context */, hidlParams));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800116}
117
118status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
119 values->clear();
120 if (!mStream) return NO_INIT;
121 hidl_vec<hidl_string> hidlKeys;
122 status_t status = keysFromHal(keys, &hidlKeys);
123 if (status != OK) return status;
124 Result retval;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800125 Return<void> ret = utils::getParameters(
126 mStream,
127 {} /* context */,
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800128 hidlKeys,
129 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
130 retval = r;
131 if (retval == Result::OK) {
132 parametersToHal(parameters, values);
133 }
134 });
135 return processReturn("getParameters", ret, retval);
136}
137
138status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
139 if (!mStream) return NO_INIT;
140 return processReturn("addEffect", mStream->addEffect(
141 static_cast<EffectHalHidl*>(effect.get())->effectId()));
142}
143
144status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
145 if (!mStream) return NO_INIT;
146 return processReturn("removeEffect", mStream->removeEffect(
147 static_cast<EffectHalHidl*>(effect.get())->effectId()));
148}
149
150status_t StreamHalHidl::standby() {
151 if (!mStream) return NO_INIT;
152 return processReturn("standby", mStream->standby());
153}
154
155status_t StreamHalHidl::dump(int fd) {
156 if (!mStream) return NO_INIT;
157 native_handle_t* hidlHandle = native_handle_create(1, 0);
158 hidlHandle->data[0] = fd;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800159 Return<void> ret = mStream->debug(hidlHandle, {} /* options */);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800160 native_handle_delete(hidlHandle);
161 mStreamPowerLog.dump(fd);
162 return processReturn("dump", ret);
163}
164
165status_t StreamHalHidl::start() {
166 if (!mStream) return NO_INIT;
167 return processReturn("start", mStream->start());
168}
169
170status_t StreamHalHidl::stop() {
171 if (!mStream) return NO_INIT;
172 return processReturn("stop", mStream->stop());
173}
174
175status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
176 struct audio_mmap_buffer_info *info) {
177 Result retval;
178 Return<void> ret = mStream->createMmapBuffer(
179 minSizeFrames,
180 [&](Result r, const MmapBufferInfo& hidlInfo) {
181 retval = r;
182 if (retval == Result::OK) {
183 const native_handle *handle = hidlInfo.sharedMemory.handle();
184 if (handle->numFds > 0) {
185 info->shared_memory_fd = handle->data[0];
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800186#if MAJOR_VERSION >= 4
Kevin Rocard734334f2018-07-12 19:37:41 -0700187 info->flags = audio_mmap_buffer_flag(hidlInfo.flags);
188#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800189 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
Kevin Rocard734334f2018-07-12 19:37:41 -0700190 // Negative buffer size frame was a hack in O and P to
191 // indicate that the buffer is shareable to applications
192 if (info->buffer_size_frames < 0) {
193 info->buffer_size_frames *= -1;
194 info->flags = audio_mmap_buffer_flag(
195 info->flags | AUDIO_MMAP_APPLICATION_SHAREABLE);
196 }
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800197 info->burst_size_frames = hidlInfo.burstSizeFrames;
198 // info->shared_memory_address is not needed in HIDL context
199 info->shared_memory_address = NULL;
200 } else {
201 retval = Result::NOT_INITIALIZED;
202 }
203 }
204 });
205 return processReturn("createMmapBuffer", ret, retval);
206}
207
208status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
209 Result retval;
210 Return<void> ret = mStream->getMmapPosition(
211 [&](Result r, const MmapPosition& hidlPosition) {
212 retval = r;
213 if (retval == Result::OK) {
214 position->time_nanoseconds = hidlPosition.timeNanoseconds;
215 position->position_frames = hidlPosition.positionFrames;
216 }
217 });
218 return processReturn("getMmapPosition", ret, retval);
219}
220
221status_t StreamHalHidl::setHalThreadPriority(int priority) {
222 mHalThreadPriority = priority;
223 return OK;
224}
225
226status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
227 if (mCachedBufferSize != 0) {
228 *size = mCachedBufferSize;
229 return OK;
230 }
231 return getBufferSize(size);
232}
233
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000234status_t StreamHalHidl::getHalPid(pid_t *pid) {
235 using ::android::hidl::base::V1_0::DebugInfo;
236 using ::android::hidl::manager::V1_0::IServiceManager;
237
238 DebugInfo debugInfo;
239 auto ret = mStream->getDebugInfo([&] (const auto &info) {
240 debugInfo = info;
241 });
242 if (!ret.isOk()) {
243 return INVALID_OPERATION;
244 }
245 if (debugInfo.pid != (int)IServiceManager::PidConstant::NO_PID) {
246 *pid = debugInfo.pid;
247 return NO_ERROR;
248 }
249 return NAME_NOT_FOUND;
250}
251
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800252bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
253 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
254 return true;
255 }
256 int err = requestPriority(
257 threadPid, threadId,
258 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
259 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
260 mHalThreadPriority, threadPid, threadId, err);
261 // Audio will still work, but latency will be higher and sometimes unacceptable.
262 return err == 0;
263}
264
265namespace {
266
267/* Notes on callback ownership.
268
269This is how (Hw)Binder ownership model looks like. The server implementation
270is owned by Binder framework (via sp<>). Proxies are owned by clients.
271When the last proxy disappears, Binder framework releases the server impl.
272
273Thus, it is not needed to keep any references to StreamOutCallback (this is
274the server impl) -- it will live as long as HAL server holds a strong ref to
275IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
276from the destructor of StreamOutHalHidl.
277
278The callback only keeps a weak reference to the stream. The stream is owned
279by AudioFlinger.
280
281*/
282
283struct StreamOutCallback : public IStreamOutCallback {
284 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
285
286 // IStreamOutCallback implementation
287 Return<void> onWriteReady() override {
288 sp<StreamOutHalHidl> stream = mStream.promote();
289 if (stream != 0) {
290 stream->onWriteReady();
291 }
292 return Void();
293 }
294
295 Return<void> onDrainReady() override {
296 sp<StreamOutHalHidl> stream = mStream.promote();
297 if (stream != 0) {
298 stream->onDrainReady();
299 }
300 return Void();
301 }
302
303 Return<void> onError() override {
304 sp<StreamOutHalHidl> stream = mStream.promote();
305 if (stream != 0) {
306 stream->onError();
307 }
308 return Void();
309 }
310
311 private:
Andy Hung638f45b2021-01-18 20:02:56 -0800312 const wp<StreamOutHalHidl> mStream;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800313};
314
315} // namespace
316
317StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
318 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
319}
320
321StreamOutHalHidl::~StreamOutHalHidl() {
322 if (mStream != 0) {
Andy Hung638f45b2021-01-18 20:02:56 -0800323 if (mCallback.load().unsafe_get()) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800324 processReturn("clearCallback", mStream->clearCallback());
325 }
jiabinf6eb4c32020-02-25 14:06:25 -0800326#if MAJOR_VERSION >= 6
Andy Hung638f45b2021-01-18 20:02:56 -0800327 if (mEventCallback.load().unsafe_get() != nullptr) {
jiabinf6eb4c32020-02-25 14:06:25 -0800328 processReturn("setEventCallback",
329 mStream->setEventCallback(nullptr));
330 }
331#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800332 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800333 }
Andy Hung638f45b2021-01-18 20:02:56 -0800334 mCallback = nullptr;
335 mEventCallback = nullptr;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800336 if (mEfGroup) {
337 EventFlag::deleteEventFlag(&mEfGroup);
338 }
339}
340
341status_t StreamOutHalHidl::getFrameSize(size_t *size) {
342 if (mStream == 0) return NO_INIT;
343 return processReturn("getFrameSize", mStream->getFrameSize(), size);
344}
345
346status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
347 if (mStream == 0) return NO_INIT;
348 if (mWriterClient == gettid() && mCommandMQ) {
349 return callWriterThread(
350 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
351 [&](const WriteStatus& writeStatus) {
352 *latency = writeStatus.reply.latencyMs;
353 });
354 } else {
355 return processReturn("getLatency", mStream->getLatency(), latency);
356 }
357}
358
359status_t StreamOutHalHidl::setVolume(float left, float right) {
360 if (mStream == 0) return NO_INIT;
361 return processReturn("setVolume", mStream->setVolume(left, right));
362}
363
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800364#if MAJOR_VERSION == 2
365status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
366 if (mStream == 0) return NO_INIT;
367 std::vector<ParameterValue> parameters;
368 String8 halParameters;
369 parameters.push_back({AudioParameter::keyPresentationId, std::to_string(presentationId)});
370 parameters.push_back({AudioParameter::keyProgramId, std::to_string(programId)});
371 parametersToHal(hidl_vec<ParameterValue>(parameters), &halParameters);
372 return setParameters(halParameters);
373}
Kevin Rocard1cf6b4d2018-11-20 18:05:44 -0800374#elif MAJOR_VERSION >= 4
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800375status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
376 if (mStream == 0) return NO_INIT;
377 return processReturn("selectPresentation",
378 mStream->selectPresentation(presentationId, programId));
379}
380#endif
381
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800382status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
383 if (mStream == 0) return NO_INIT;
384 *written = 0;
385
386 if (bytes == 0 && !mDataMQ) {
387 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
Andy Hung638f45b2021-01-18 20:02:56 -0800388 ALOGW_IF(mCallback.load().unsafe_get(), "First call to async write with 0 bytes");
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800389 return OK;
390 }
391
392 status_t status;
393 if (!mDataMQ) {
394 // In case if playback starts close to the end of a compressed track, the bytes
395 // that need to be written is less than the actual buffer size. Need to use
396 // full buffer size for the MQ since otherwise after seeking back to the middle
397 // data will be truncated.
398 size_t bufferSize;
399 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
400 return status;
401 }
402 if (bytes > bufferSize) bufferSize = bytes;
403 if ((status = prepareForWriting(bufferSize)) != OK) {
404 return status;
405 }
406 }
407
408 status = callWriterThread(
409 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
410 [&] (const WriteStatus& writeStatus) {
411 *written = writeStatus.reply.written;
412 // Diagnostics of the cause of b/35813113.
413 ALOGE_IF(*written > bytes,
414 "hal reports more bytes written than asked for: %lld > %lld",
415 (long long)*written, (long long)bytes);
416 });
417 mStreamPowerLog.log(buffer, *written);
418 return status;
419}
420
421status_t StreamOutHalHidl::callWriterThread(
422 WriteCommand cmd, const char* cmdName,
423 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
424 if (!mCommandMQ->write(&cmd)) {
425 ALOGE("command message queue write failed for \"%s\"", cmdName);
426 return -EAGAIN;
427 }
428 if (data != nullptr) {
429 size_t availableToWrite = mDataMQ->availableToWrite();
430 if (dataSize > availableToWrite) {
431 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
432 (long long)dataSize, (long long)availableToWrite);
433 dataSize = availableToWrite;
434 }
435 if (!mDataMQ->write(data, dataSize)) {
436 ALOGE("data message queue write failed for \"%s\"", cmdName);
437 }
438 }
439 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
440
441 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
442 uint32_t efState = 0;
443retry:
444 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
445 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
446 WriteStatus writeStatus;
447 writeStatus.retval = Result::NOT_INITIALIZED;
448 if (!mStatusMQ->read(&writeStatus)) {
449 ALOGE("status message read failed for \"%s\"", cmdName);
450 }
451 if (writeStatus.retval == Result::OK) {
452 ret = OK;
453 callback(writeStatus);
454 } else {
455 ret = processReturn(cmdName, writeStatus.retval);
456 }
457 return ret;
458 }
459 if (ret == -EAGAIN || ret == -EINTR) {
460 // Spurious wakeup. This normally retries no more than once.
461 goto retry;
462 }
463 return ret;
464}
465
466status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
467 std::unique_ptr<CommandMQ> tempCommandMQ;
468 std::unique_ptr<DataMQ> tempDataMQ;
469 std::unique_ptr<StatusMQ> tempStatusMQ;
470 Result retval;
471 pid_t halThreadPid, halThreadTid;
472 Return<void> ret = mStream->prepareForWriting(
473 1, bufferSize,
474 [&](Result r,
475 const CommandMQ::Descriptor& commandMQ,
476 const DataMQ::Descriptor& dataMQ,
477 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000478 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800479 retval = r;
480 if (retval == Result::OK) {
481 tempCommandMQ.reset(new CommandMQ(commandMQ));
482 tempDataMQ.reset(new DataMQ(dataMQ));
483 tempStatusMQ.reset(new StatusMQ(statusMQ));
484 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
485 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
486 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000487#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800488 halThreadPid = halThreadInfo.pid;
489 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000490#else
491 halThreadTid = halThreadInfo;
492#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800493 }
494 });
495 if (!ret.isOk() || retval != Result::OK) {
496 return processReturn("prepareForWriting", ret, retval);
497 }
498 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
499 !tempDataMQ || !tempDataMQ->isValid() ||
500 !tempStatusMQ || !tempStatusMQ->isValid() ||
501 !mEfGroup) {
502 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
503 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
504 "Command message queue for writing is invalid");
505 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
506 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
507 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
508 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
509 "Status message queue for writing is invalid");
510 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
511 return NO_INIT;
512 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000513#if MAJOR_VERSION >= 7
514 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
515 return status;
516 }
517#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800518 requestHalThreadPriority(halThreadPid, halThreadTid);
519
520 mCommandMQ = std::move(tempCommandMQ);
521 mDataMQ = std::move(tempDataMQ);
522 mStatusMQ = std::move(tempStatusMQ);
523 mWriterClient = gettid();
524 return OK;
525}
526
527status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
528 if (mStream == 0) return NO_INIT;
529 Result retval;
530 Return<void> ret = mStream->getRenderPosition(
531 [&](Result r, uint32_t d) {
532 retval = r;
533 if (retval == Result::OK) {
534 *dspFrames = d;
535 }
536 });
537 return processReturn("getRenderPosition", ret, retval);
538}
539
540status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
541 if (mStream == 0) return NO_INIT;
542 Result retval;
543 Return<void> ret = mStream->getNextWriteTimestamp(
544 [&](Result r, int64_t t) {
545 retval = r;
546 if (retval == Result::OK) {
547 *timestamp = t;
548 }
549 });
550 return processReturn("getRenderPosition", ret, retval);
551}
552
553status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
554 if (mStream == 0) return NO_INIT;
555 status_t status = processReturn(
556 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
557 if (status == OK) {
558 mCallback = callback;
559 }
560 return status;
561}
562
563status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
564 if (mStream == 0) return NO_INIT;
565 Return<void> ret = mStream->supportsPauseAndResume(
566 [&](bool p, bool r) {
567 *supportsPause = p;
568 *supportsResume = r;
569 });
570 return processReturn("supportsPauseAndResume", ret);
571}
572
573status_t StreamOutHalHidl::pause() {
574 if (mStream == 0) return NO_INIT;
575 return processReturn("pause", mStream->pause());
576}
577
578status_t StreamOutHalHidl::resume() {
579 if (mStream == 0) return NO_INIT;
580 return processReturn("pause", mStream->resume());
581}
582
583status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
584 if (mStream == 0) return NO_INIT;
585 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
586}
587
588status_t StreamOutHalHidl::drain(bool earlyNotify) {
589 if (mStream == 0) return NO_INIT;
590 return processReturn(
591 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
592}
593
594status_t StreamOutHalHidl::flush() {
595 if (mStream == 0) return NO_INIT;
596 return processReturn("pause", mStream->flush());
597}
598
599status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
600 if (mStream == 0) return NO_INIT;
601 if (mWriterClient == gettid() && mCommandMQ) {
602 return callWriterThread(
603 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
604 [&](const WriteStatus& writeStatus) {
605 *frames = writeStatus.reply.presentationPosition.frames;
606 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
607 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
608 });
609 } else {
610 Result retval;
611 Return<void> ret = mStream->getPresentationPosition(
612 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
613 retval = r;
614 if (retval == Result::OK) {
615 *frames = hidlFrames;
616 timestamp->tv_sec = hidlTimeStamp.tvSec;
617 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
618 }
619 });
620 return processReturn("getPresentationPosition", ret, retval);
621 }
622}
623
Kevin Rocard070e7512018-05-22 09:29:13 -0700624#if MAJOR_VERSION == 2
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800625status_t StreamOutHalHidl::updateSourceMetadata(
626 const StreamOutHalInterface::SourceMetadata& /* sourceMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700627 // Audio HAL V2.0 does not support propagating source metadata
628 return INVALID_OPERATION;
629}
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800630#elif MAJOR_VERSION >= 4
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800631status_t StreamOutHalHidl::updateSourceMetadata(
632 const StreamOutHalInterface::SourceMetadata& sourceMetadata) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000633 CPP_VERSION::SourceMetadata hidlMetadata;
634 if (status_t status = CoreUtils::sourceMetadataFromHalV7(
635 sourceMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
636 status != OK) {
637 return status;
638 }
639 return processReturn("updateSourceMetadata", mStream->updateSourceMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -0700640}
Kevin Rocard070e7512018-05-22 09:29:13 -0700641#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700642
jiabinf6eb4c32020-02-25 14:06:25 -0800643#if MAJOR_VERSION < 6
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800644status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode __unused) {
645 return INVALID_OPERATION;
646}
647
648status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode __unused) {
649 return INVALID_OPERATION;
650}
651
652status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB __unused) {
653 return INVALID_OPERATION;
654}
655
656status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB __unused) {
657 return INVALID_OPERATION;
658}
659
660status_t StreamOutHalHidl::getPlaybackRateParameters(
661 audio_playback_rate_t* playbackRate __unused) {
662 return INVALID_OPERATION;
663}
664
665status_t StreamOutHalHidl::setPlaybackRateParameters(
666 const audio_playback_rate_t& playbackRate __unused) {
667 return INVALID_OPERATION;
668}
669
jiabinf6eb4c32020-02-25 14:06:25 -0800670status_t StreamOutHalHidl::setEventCallback(
671 const sp<StreamOutHalInterfaceEventCallback>& callback __unused) {
672 // Codec format callback is supported starting from audio HAL V6.0
673 return INVALID_OPERATION;
674}
675#else
676
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800677status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode) {
678 if (mStream == 0) return NO_INIT;
679 Result retval;
680 Return<void> ret = mStream->getDualMonoMode(
681 [&](Result r, DualMonoMode hidlMode) {
682 retval = r;
683 if (retval == Result::OK) {
684 *mode = static_cast<audio_dual_mono_mode_t>(hidlMode);
685 }
686 });
687 return processReturn("getDualMonoMode", ret, retval);
688}
689
690status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode) {
691 if (mStream == 0) return NO_INIT;
692 return processReturn(
693 "setDualMonoMode", mStream->setDualMonoMode(static_cast<DualMonoMode>(mode)));
694}
695
696status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB) {
697 if (mStream == 0) return NO_INIT;
698 Result retval;
699 Return<void> ret = mStream->getAudioDescriptionMixLevel(
700 [&](Result r, float hidlLeveldB) {
701 retval = r;
702 if (retval == Result::OK) {
703 *leveldB = hidlLeveldB;
704 }
705 });
706 return processReturn("getAudioDescriptionMixLevel", ret, retval);
707}
708
709status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB) {
710 if (mStream == 0) return NO_INIT;
711 return processReturn(
712 "setAudioDescriptionMixLevel", mStream->setAudioDescriptionMixLevel(leveldB));
713}
714
715status_t StreamOutHalHidl::getPlaybackRateParameters(audio_playback_rate_t* playbackRate) {
716 if (mStream == 0) return NO_INIT;
717 Result retval;
718 Return<void> ret = mStream->getPlaybackRateParameters(
719 [&](Result r, PlaybackRate hidlPlaybackRate) {
720 retval = r;
721 if (retval == Result::OK) {
722 playbackRate->mSpeed = hidlPlaybackRate.speed;
723 playbackRate->mPitch = hidlPlaybackRate.pitch;
724 playbackRate->mStretchMode =
725 static_cast<audio_timestretch_stretch_mode_t>(
726 hidlPlaybackRate.timestretchMode);
727 playbackRate->mFallbackMode =
728 static_cast<audio_timestretch_fallback_mode_t>(
729 hidlPlaybackRate.fallbackMode);
730 }
731 });
732 return processReturn("getPlaybackRateParameters", ret, retval);
733}
734
735status_t StreamOutHalHidl::setPlaybackRateParameters(const audio_playback_rate_t& playbackRate) {
736 if (mStream == 0) return NO_INIT;
737 return processReturn(
738 "setPlaybackRateParameters", mStream->setPlaybackRateParameters(
739 PlaybackRate{playbackRate.mSpeed, playbackRate.mPitch,
740 static_cast<TimestretchMode>(playbackRate.mStretchMode),
741 static_cast<TimestretchFallbackMode>(playbackRate.mFallbackMode)}));
742}
743
jiabinf6eb4c32020-02-25 14:06:25 -0800744#include PATH(android/hardware/audio/FILE_VERSION/IStreamOutEventCallback.h)
745
746namespace {
747
748struct StreamOutEventCallback : public IStreamOutEventCallback {
749 StreamOutEventCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
750
751 // IStreamOutEventCallback implementation
752 Return<void> onCodecFormatChanged(
753 const android::hardware::hidl_vec<uint8_t>& audioMetadata) override {
754 sp<StreamOutHalHidl> stream = mStream.promote();
755 if (stream != nullptr) {
756 std::basic_string<uint8_t> metadataBs(audioMetadata.begin(), audioMetadata.end());
757 stream->onCodecFormatChanged(metadataBs);
758 }
759 return Void();
760 }
761
762 private:
763 wp<StreamOutHalHidl> mStream;
764};
765
766} // namespace
767
768status_t StreamOutHalHidl::setEventCallback(
769 const sp<StreamOutHalInterfaceEventCallback>& callback) {
770 if (mStream == nullptr) return NO_INIT;
771 mEventCallback = callback;
772 status_t status = processReturn(
773 "setEventCallback",
774 mStream->setEventCallback(
775 callback.get() == nullptr ? nullptr : new StreamOutEventCallback(this)));
776 return status;
777}
778#endif
779
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800780void StreamOutHalHidl::onWriteReady() {
Andy Hung638f45b2021-01-18 20:02:56 -0800781 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800782 if (callback == 0) return;
783 ALOGV("asyncCallback onWriteReady");
784 callback->onWriteReady();
785}
786
787void StreamOutHalHidl::onDrainReady() {
Andy Hung638f45b2021-01-18 20:02:56 -0800788 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800789 if (callback == 0) return;
790 ALOGV("asyncCallback onDrainReady");
791 callback->onDrainReady();
792}
793
794void StreamOutHalHidl::onError() {
Andy Hung638f45b2021-01-18 20:02:56 -0800795 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800796 if (callback == 0) return;
797 ALOGV("asyncCallback onError");
798 callback->onError();
799}
800
jiabinf6eb4c32020-02-25 14:06:25 -0800801void StreamOutHalHidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) {
Andy Hung638f45b2021-01-18 20:02:56 -0800802 sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.load().promote();
jiabinf6eb4c32020-02-25 14:06:25 -0800803 if (callback == nullptr) return;
804 ALOGV("asyncCodecFormatCallback %s", __func__);
805 callback->onCodecFormatChanged(metadataBs);
806}
807
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800808
809StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
810 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
811}
812
813StreamInHalHidl::~StreamInHalHidl() {
814 if (mStream != 0) {
815 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800816 }
817 if (mEfGroup) {
818 EventFlag::deleteEventFlag(&mEfGroup);
819 }
820}
821
822status_t StreamInHalHidl::getFrameSize(size_t *size) {
823 if (mStream == 0) return NO_INIT;
824 return processReturn("getFrameSize", mStream->getFrameSize(), size);
825}
826
827status_t StreamInHalHidl::setGain(float gain) {
828 if (mStream == 0) return NO_INIT;
829 return processReturn("setGain", mStream->setGain(gain));
830}
831
832status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
833 if (mStream == 0) return NO_INIT;
834 *read = 0;
835
836 if (bytes == 0 && !mDataMQ) {
837 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
838 return OK;
839 }
840
841 status_t status;
842 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
843 return status;
844 }
845
846 ReadParameters params;
847 params.command = ReadCommand::READ;
848 params.params.read = bytes;
849 status = callReaderThread(params, "read",
850 [&](const ReadStatus& readStatus) {
851 const size_t availToRead = mDataMQ->availableToRead();
852 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
853 ALOGE("data message queue read failed for \"read\"");
854 }
855 ALOGW_IF(availToRead != readStatus.reply.read,
856 "HAL read report inconsistent: mq = %d, status = %d",
857 (int32_t)availToRead, (int32_t)readStatus.reply.read);
858 *read = readStatus.reply.read;
859 });
860 mStreamPowerLog.log(buffer, *read);
861 return status;
862}
863
864status_t StreamInHalHidl::callReaderThread(
865 const ReadParameters& params, const char* cmdName,
866 StreamInHalHidl::ReaderCallback callback) {
867 if (!mCommandMQ->write(&params)) {
868 ALOGW("command message queue write failed");
869 return -EAGAIN;
870 }
871 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
872
873 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
874 uint32_t efState = 0;
875retry:
876 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
877 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
878 ReadStatus readStatus;
879 readStatus.retval = Result::NOT_INITIALIZED;
880 if (!mStatusMQ->read(&readStatus)) {
881 ALOGE("status message read failed for \"%s\"", cmdName);
882 }
883 if (readStatus.retval == Result::OK) {
884 ret = OK;
885 callback(readStatus);
886 } else {
887 ret = processReturn(cmdName, readStatus.retval);
888 }
889 return ret;
890 }
891 if (ret == -EAGAIN || ret == -EINTR) {
892 // Spurious wakeup. This normally retries no more than once.
893 goto retry;
894 }
895 return ret;
896}
897
898status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
899 std::unique_ptr<CommandMQ> tempCommandMQ;
900 std::unique_ptr<DataMQ> tempDataMQ;
901 std::unique_ptr<StatusMQ> tempStatusMQ;
902 Result retval;
903 pid_t halThreadPid, halThreadTid;
904 Return<void> ret = mStream->prepareForReading(
905 1, bufferSize,
906 [&](Result r,
907 const CommandMQ::Descriptor& commandMQ,
908 const DataMQ::Descriptor& dataMQ,
909 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000910 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800911 retval = r;
912 if (retval == Result::OK) {
913 tempCommandMQ.reset(new CommandMQ(commandMQ));
914 tempDataMQ.reset(new DataMQ(dataMQ));
915 tempStatusMQ.reset(new StatusMQ(statusMQ));
916 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
917 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
918 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000919#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800920 halThreadPid = halThreadInfo.pid;
921 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000922#else
923 halThreadTid = halThreadInfo;
924#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800925 }
926 });
927 if (!ret.isOk() || retval != Result::OK) {
928 return processReturn("prepareForReading", ret, retval);
929 }
930 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
931 !tempDataMQ || !tempDataMQ->isValid() ||
932 !tempStatusMQ || !tempStatusMQ->isValid() ||
933 !mEfGroup) {
934 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
935 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
936 "Command message queue for writing is invalid");
937 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
938 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
939 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
940 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
941 "Status message queue for reading is invalid");
942 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
943 return NO_INIT;
944 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000945#if MAJOR_VERSION >= 7
946 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
947 return status;
948 }
949#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800950 requestHalThreadPriority(halThreadPid, halThreadTid);
951
952 mCommandMQ = std::move(tempCommandMQ);
953 mDataMQ = std::move(tempDataMQ);
954 mStatusMQ = std::move(tempStatusMQ);
955 mReaderClient = gettid();
956 return OK;
957}
958
959status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
960 if (mStream == 0) return NO_INIT;
961 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
962}
963
964status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
965 if (mStream == 0) return NO_INIT;
966 if (mReaderClient == gettid() && mCommandMQ) {
967 ReadParameters params;
968 params.command = ReadCommand::GET_CAPTURE_POSITION;
969 return callReaderThread(params, "getCapturePosition",
970 [&](const ReadStatus& readStatus) {
971 *frames = readStatus.reply.capturePosition.frames;
972 *time = readStatus.reply.capturePosition.time;
973 });
974 } else {
975 Result retval;
976 Return<void> ret = mStream->getCapturePosition(
977 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
978 retval = r;
979 if (retval == Result::OK) {
980 *frames = hidlFrames;
981 *time = hidlTime;
982 }
983 });
984 return processReturn("getCapturePosition", ret, retval);
985 }
986}
987
Kevin Rocard070e7512018-05-22 09:29:13 -0700988#if MAJOR_VERSION == 2
989status_t StreamInHalHidl::getActiveMicrophones(
990 std::vector<media::MicrophoneInfo> *microphones __unused) {
991 if (mStream == 0) return NO_INIT;
992 return INVALID_OPERATION;
993}
994
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800995status_t StreamInHalHidl::updateSinkMetadata(
996 const StreamInHalInterface::SinkMetadata& /* sinkMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700997 // Audio HAL V2.0 does not support propagating sink metadata
998 return INVALID_OPERATION;
999}
1000
Kevin Rocard3d48dce2018-11-08 17:16:57 -08001001#elif MAJOR_VERSION >= 4
jiabin9ff780e2018-03-19 18:19:52 -07001002status_t StreamInHalHidl::getActiveMicrophones(
1003 std::vector<media::MicrophoneInfo> *microphonesInfo) {
1004 if (!mStream) return NO_INIT;
1005 Result retval;
1006 Return<void> ret = mStream->getActiveMicrophones(
1007 [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
1008 retval = r;
1009 for (size_t k = 0; k < micArrayHal.size(); k++) {
1010 audio_microphone_characteristic_t dst;
1011 // convert
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001012 (void)CoreUtils::microphoneInfoToHal(micArrayHal[k], &dst);
jiabin9ff780e2018-03-19 18:19:52 -07001013 media::MicrophoneInfo microphone = media::MicrophoneInfo(dst);
1014 microphonesInfo->push_back(microphone);
1015 }
1016 });
1017 return processReturn("getActiveMicrophones", ret, retval);
1018}
1019
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001020status_t StreamInHalHidl::updateSinkMetadata(const
1021 StreamInHalInterface::SinkMetadata& sinkMetadata) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001022 CPP_VERSION::SinkMetadata hidlMetadata;
1023 if (status_t status = CoreUtils::sinkMetadataFromHalV7(
1024 sinkMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
1025 status != OK) {
1026 return status;
1027 }
1028 return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -07001029}
Kevin Rocard070e7512018-05-22 09:29:13 -07001030#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -07001031
Paul McLean03a6e6a2018-12-04 10:54:13 -07001032#if MAJOR_VERSION < 5
Paul McLean12340082019-03-19 09:35:05 -06001033status_t StreamInHalHidl::setPreferredMicrophoneDirection(
1034 audio_microphone_direction_t direction __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001035 if (mStream == 0) return NO_INIT;
1036 return INVALID_OPERATION;
1037}
1038
Paul McLean12340082019-03-19 09:35:05 -06001039status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001040 if (mStream == 0) return NO_INIT;
1041 return INVALID_OPERATION;
1042}
1043#else
Paul McLean12340082019-03-19 09:35:05 -06001044status_t StreamInHalHidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001045 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001046 return processReturn("setPreferredMicrophoneDirection",
1047 mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction)));
Paul McLean03a6e6a2018-12-04 10:54:13 -07001048}
1049
Paul McLean12340082019-03-19 09:35:05 -06001050status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001051 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001052 return processReturn("setPreferredMicrophoneFieldDimension",
Paul McLean03a6e6a2018-12-04 10:54:13 -07001053 mStream->setMicrophoneFieldDimension(zoom));
1054}
1055#endif
1056
Kevin Rocard070e7512018-05-22 09:29:13 -07001057} // namespace CPP_VERSION
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001058} // namespace android