blob: 129b1c1fb14eda3563f2ec82b5214ccb201e393d [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);
Andy Hunge72ff022021-08-16 10:16:15 -0700161
162 // TODO(b/111997867, b/177271958) Workaround - remove when fixed.
163 // A Binder transmitted fd may not close immediately due to a race condition b/111997867
164 // when the remote binder thread removes the last refcount to the fd blocks in the
165 // kernel for binder activity. We send a Binder ping() command to unblock the thread
166 // and complete the fd close / release.
167 //
168 // See DeviceHalHidl::dump(), EffectHalHidl::dump(), StreamHalHidl::dump(),
169 // EffectsFactoryHalHidl::dumpEffects().
170
171 (void)mStream->ping(); // synchronous Binder call
172
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800173 mStreamPowerLog.dump(fd);
174 return processReturn("dump", ret);
175}
176
177status_t StreamHalHidl::start() {
178 if (!mStream) return NO_INIT;
179 return processReturn("start", mStream->start());
180}
181
182status_t StreamHalHidl::stop() {
183 if (!mStream) return NO_INIT;
184 return processReturn("stop", mStream->stop());
185}
186
187status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
188 struct audio_mmap_buffer_info *info) {
189 Result retval;
190 Return<void> ret = mStream->createMmapBuffer(
191 minSizeFrames,
192 [&](Result r, const MmapBufferInfo& hidlInfo) {
193 retval = r;
194 if (retval == Result::OK) {
195 const native_handle *handle = hidlInfo.sharedMemory.handle();
196 if (handle->numFds > 0) {
197 info->shared_memory_fd = handle->data[0];
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800198#if MAJOR_VERSION >= 4
Kevin Rocard734334f2018-07-12 19:37:41 -0700199 info->flags = audio_mmap_buffer_flag(hidlInfo.flags);
200#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800201 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
Kevin Rocard734334f2018-07-12 19:37:41 -0700202 // Negative buffer size frame was a hack in O and P to
203 // indicate that the buffer is shareable to applications
204 if (info->buffer_size_frames < 0) {
205 info->buffer_size_frames *= -1;
206 info->flags = audio_mmap_buffer_flag(
207 info->flags | AUDIO_MMAP_APPLICATION_SHAREABLE);
208 }
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800209 info->burst_size_frames = hidlInfo.burstSizeFrames;
210 // info->shared_memory_address is not needed in HIDL context
211 info->shared_memory_address = NULL;
212 } else {
213 retval = Result::NOT_INITIALIZED;
214 }
215 }
216 });
217 return processReturn("createMmapBuffer", ret, retval);
218}
219
220status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
221 Result retval;
222 Return<void> ret = mStream->getMmapPosition(
223 [&](Result r, const MmapPosition& hidlPosition) {
224 retval = r;
225 if (retval == Result::OK) {
226 position->time_nanoseconds = hidlPosition.timeNanoseconds;
227 position->position_frames = hidlPosition.positionFrames;
228 }
229 });
230 return processReturn("getMmapPosition", ret, retval);
231}
232
233status_t StreamHalHidl::setHalThreadPriority(int priority) {
234 mHalThreadPriority = priority;
235 return OK;
236}
237
238status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
239 if (mCachedBufferSize != 0) {
240 *size = mCachedBufferSize;
241 return OK;
242 }
243 return getBufferSize(size);
244}
245
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000246status_t StreamHalHidl::getHalPid(pid_t *pid) {
247 using ::android::hidl::base::V1_0::DebugInfo;
248 using ::android::hidl::manager::V1_0::IServiceManager;
249
250 DebugInfo debugInfo;
251 auto ret = mStream->getDebugInfo([&] (const auto &info) {
252 debugInfo = info;
253 });
254 if (!ret.isOk()) {
255 return INVALID_OPERATION;
256 }
257 if (debugInfo.pid != (int)IServiceManager::PidConstant::NO_PID) {
258 *pid = debugInfo.pid;
259 return NO_ERROR;
260 }
261 return NAME_NOT_FOUND;
262}
263
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800264bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
265 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
266 return true;
267 }
268 int err = requestPriority(
269 threadPid, threadId,
270 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
271 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
272 mHalThreadPriority, threadPid, threadId, err);
273 // Audio will still work, but latency will be higher and sometimes unacceptable.
274 return err == 0;
275}
276
277namespace {
278
279/* Notes on callback ownership.
280
281This is how (Hw)Binder ownership model looks like. The server implementation
282is owned by Binder framework (via sp<>). Proxies are owned by clients.
283When the last proxy disappears, Binder framework releases the server impl.
284
285Thus, it is not needed to keep any references to StreamOutCallback (this is
286the server impl) -- it will live as long as HAL server holds a strong ref to
287IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
288from the destructor of StreamOutHalHidl.
289
290The callback only keeps a weak reference to the stream. The stream is owned
291by AudioFlinger.
292
293*/
294
295struct StreamOutCallback : public IStreamOutCallback {
296 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
297
298 // IStreamOutCallback implementation
299 Return<void> onWriteReady() override {
300 sp<StreamOutHalHidl> stream = mStream.promote();
301 if (stream != 0) {
302 stream->onWriteReady();
303 }
304 return Void();
305 }
306
307 Return<void> onDrainReady() override {
308 sp<StreamOutHalHidl> stream = mStream.promote();
309 if (stream != 0) {
310 stream->onDrainReady();
311 }
312 return Void();
313 }
314
315 Return<void> onError() override {
316 sp<StreamOutHalHidl> stream = mStream.promote();
317 if (stream != 0) {
318 stream->onError();
319 }
320 return Void();
321 }
322
323 private:
Andy Hung638f45b2021-01-18 20:02:56 -0800324 const wp<StreamOutHalHidl> mStream;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800325};
326
327} // namespace
328
329StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
330 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
331}
332
333StreamOutHalHidl::~StreamOutHalHidl() {
334 if (mStream != 0) {
Andy Hung638f45b2021-01-18 20:02:56 -0800335 if (mCallback.load().unsafe_get()) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800336 processReturn("clearCallback", mStream->clearCallback());
337 }
jiabinf6eb4c32020-02-25 14:06:25 -0800338#if MAJOR_VERSION >= 6
Andy Hung638f45b2021-01-18 20:02:56 -0800339 if (mEventCallback.load().unsafe_get() != nullptr) {
jiabinf6eb4c32020-02-25 14:06:25 -0800340 processReturn("setEventCallback",
341 mStream->setEventCallback(nullptr));
342 }
343#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800344 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800345 }
Andy Hung638f45b2021-01-18 20:02:56 -0800346 mCallback = nullptr;
347 mEventCallback = nullptr;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800348 if (mEfGroup) {
349 EventFlag::deleteEventFlag(&mEfGroup);
350 }
351}
352
353status_t StreamOutHalHidl::getFrameSize(size_t *size) {
354 if (mStream == 0) return NO_INIT;
355 return processReturn("getFrameSize", mStream->getFrameSize(), size);
356}
357
358status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
359 if (mStream == 0) return NO_INIT;
360 if (mWriterClient == gettid() && mCommandMQ) {
361 return callWriterThread(
362 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
363 [&](const WriteStatus& writeStatus) {
364 *latency = writeStatus.reply.latencyMs;
365 });
366 } else {
367 return processReturn("getLatency", mStream->getLatency(), latency);
368 }
369}
370
371status_t StreamOutHalHidl::setVolume(float left, float right) {
372 if (mStream == 0) return NO_INIT;
373 return processReturn("setVolume", mStream->setVolume(left, right));
374}
375
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800376#if MAJOR_VERSION == 2
377status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
378 if (mStream == 0) return NO_INIT;
379 std::vector<ParameterValue> parameters;
380 String8 halParameters;
381 parameters.push_back({AudioParameter::keyPresentationId, std::to_string(presentationId)});
382 parameters.push_back({AudioParameter::keyProgramId, std::to_string(programId)});
383 parametersToHal(hidl_vec<ParameterValue>(parameters), &halParameters);
384 return setParameters(halParameters);
385}
Kevin Rocard1cf6b4d2018-11-20 18:05:44 -0800386#elif MAJOR_VERSION >= 4
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800387status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
388 if (mStream == 0) return NO_INIT;
389 return processReturn("selectPresentation",
390 mStream->selectPresentation(presentationId, programId));
391}
392#endif
393
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800394status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
395 if (mStream == 0) return NO_INIT;
396 *written = 0;
397
398 if (bytes == 0 && !mDataMQ) {
399 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
Andy Hung638f45b2021-01-18 20:02:56 -0800400 ALOGW_IF(mCallback.load().unsafe_get(), "First call to async write with 0 bytes");
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800401 return OK;
402 }
403
404 status_t status;
405 if (!mDataMQ) {
406 // In case if playback starts close to the end of a compressed track, the bytes
407 // that need to be written is less than the actual buffer size. Need to use
408 // full buffer size for the MQ since otherwise after seeking back to the middle
409 // data will be truncated.
410 size_t bufferSize;
411 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
412 return status;
413 }
414 if (bytes > bufferSize) bufferSize = bytes;
415 if ((status = prepareForWriting(bufferSize)) != OK) {
416 return status;
417 }
418 }
419
420 status = callWriterThread(
421 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
422 [&] (const WriteStatus& writeStatus) {
423 *written = writeStatus.reply.written;
424 // Diagnostics of the cause of b/35813113.
425 ALOGE_IF(*written > bytes,
426 "hal reports more bytes written than asked for: %lld > %lld",
427 (long long)*written, (long long)bytes);
428 });
429 mStreamPowerLog.log(buffer, *written);
430 return status;
431}
432
433status_t StreamOutHalHidl::callWriterThread(
434 WriteCommand cmd, const char* cmdName,
435 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
436 if (!mCommandMQ->write(&cmd)) {
437 ALOGE("command message queue write failed for \"%s\"", cmdName);
438 return -EAGAIN;
439 }
440 if (data != nullptr) {
441 size_t availableToWrite = mDataMQ->availableToWrite();
442 if (dataSize > availableToWrite) {
443 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
444 (long long)dataSize, (long long)availableToWrite);
445 dataSize = availableToWrite;
446 }
447 if (!mDataMQ->write(data, dataSize)) {
448 ALOGE("data message queue write failed for \"%s\"", cmdName);
449 }
450 }
451 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
452
453 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
454 uint32_t efState = 0;
455retry:
456 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
457 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
458 WriteStatus writeStatus;
459 writeStatus.retval = Result::NOT_INITIALIZED;
460 if (!mStatusMQ->read(&writeStatus)) {
461 ALOGE("status message read failed for \"%s\"", cmdName);
462 }
463 if (writeStatus.retval == Result::OK) {
464 ret = OK;
465 callback(writeStatus);
466 } else {
467 ret = processReturn(cmdName, writeStatus.retval);
468 }
469 return ret;
470 }
471 if (ret == -EAGAIN || ret == -EINTR) {
472 // Spurious wakeup. This normally retries no more than once.
473 goto retry;
474 }
475 return ret;
476}
477
478status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
479 std::unique_ptr<CommandMQ> tempCommandMQ;
480 std::unique_ptr<DataMQ> tempDataMQ;
481 std::unique_ptr<StatusMQ> tempStatusMQ;
482 Result retval;
483 pid_t halThreadPid, halThreadTid;
484 Return<void> ret = mStream->prepareForWriting(
485 1, bufferSize,
486 [&](Result r,
487 const CommandMQ::Descriptor& commandMQ,
488 const DataMQ::Descriptor& dataMQ,
489 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000490 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800491 retval = r;
492 if (retval == Result::OK) {
493 tempCommandMQ.reset(new CommandMQ(commandMQ));
494 tempDataMQ.reset(new DataMQ(dataMQ));
495 tempStatusMQ.reset(new StatusMQ(statusMQ));
496 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
497 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
498 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000499#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800500 halThreadPid = halThreadInfo.pid;
501 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000502#else
503 halThreadTid = halThreadInfo;
504#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800505 }
506 });
507 if (!ret.isOk() || retval != Result::OK) {
508 return processReturn("prepareForWriting", ret, retval);
509 }
510 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
511 !tempDataMQ || !tempDataMQ->isValid() ||
512 !tempStatusMQ || !tempStatusMQ->isValid() ||
513 !mEfGroup) {
514 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
515 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
516 "Command message queue for writing is invalid");
517 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
518 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
519 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
520 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
521 "Status message queue for writing is invalid");
522 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
523 return NO_INIT;
524 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000525#if MAJOR_VERSION >= 7
526 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
527 return status;
528 }
529#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800530 requestHalThreadPriority(halThreadPid, halThreadTid);
531
532 mCommandMQ = std::move(tempCommandMQ);
533 mDataMQ = std::move(tempDataMQ);
534 mStatusMQ = std::move(tempStatusMQ);
535 mWriterClient = gettid();
536 return OK;
537}
538
539status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
540 if (mStream == 0) return NO_INIT;
541 Result retval;
542 Return<void> ret = mStream->getRenderPosition(
543 [&](Result r, uint32_t d) {
544 retval = r;
545 if (retval == Result::OK) {
546 *dspFrames = d;
547 }
548 });
549 return processReturn("getRenderPosition", ret, retval);
550}
551
552status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
553 if (mStream == 0) return NO_INIT;
554 Result retval;
555 Return<void> ret = mStream->getNextWriteTimestamp(
556 [&](Result r, int64_t t) {
557 retval = r;
558 if (retval == Result::OK) {
559 *timestamp = t;
560 }
561 });
562 return processReturn("getRenderPosition", ret, retval);
563}
564
565status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
566 if (mStream == 0) return NO_INIT;
567 status_t status = processReturn(
568 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
569 if (status == OK) {
570 mCallback = callback;
571 }
572 return status;
573}
574
575status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
576 if (mStream == 0) return NO_INIT;
577 Return<void> ret = mStream->supportsPauseAndResume(
578 [&](bool p, bool r) {
579 *supportsPause = p;
580 *supportsResume = r;
581 });
582 return processReturn("supportsPauseAndResume", ret);
583}
584
585status_t StreamOutHalHidl::pause() {
586 if (mStream == 0) return NO_INIT;
587 return processReturn("pause", mStream->pause());
588}
589
590status_t StreamOutHalHidl::resume() {
591 if (mStream == 0) return NO_INIT;
592 return processReturn("pause", mStream->resume());
593}
594
595status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
596 if (mStream == 0) return NO_INIT;
597 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
598}
599
600status_t StreamOutHalHidl::drain(bool earlyNotify) {
601 if (mStream == 0) return NO_INIT;
602 return processReturn(
603 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
604}
605
606status_t StreamOutHalHidl::flush() {
607 if (mStream == 0) return NO_INIT;
608 return processReturn("pause", mStream->flush());
609}
610
611status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
612 if (mStream == 0) return NO_INIT;
613 if (mWriterClient == gettid() && mCommandMQ) {
614 return callWriterThread(
615 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
616 [&](const WriteStatus& writeStatus) {
617 *frames = writeStatus.reply.presentationPosition.frames;
618 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
619 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
620 });
621 } else {
622 Result retval;
623 Return<void> ret = mStream->getPresentationPosition(
624 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
625 retval = r;
626 if (retval == Result::OK) {
627 *frames = hidlFrames;
628 timestamp->tv_sec = hidlTimeStamp.tvSec;
629 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
630 }
631 });
632 return processReturn("getPresentationPosition", ret, retval);
633 }
634}
635
Kevin Rocard070e7512018-05-22 09:29:13 -0700636#if MAJOR_VERSION == 2
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800637status_t StreamOutHalHidl::updateSourceMetadata(
638 const StreamOutHalInterface::SourceMetadata& /* sourceMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700639 // Audio HAL V2.0 does not support propagating source metadata
640 return INVALID_OPERATION;
641}
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800642#elif MAJOR_VERSION >= 4
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800643status_t StreamOutHalHidl::updateSourceMetadata(
644 const StreamOutHalInterface::SourceMetadata& sourceMetadata) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000645 CPP_VERSION::SourceMetadata hidlMetadata;
646 if (status_t status = CoreUtils::sourceMetadataFromHalV7(
647 sourceMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
648 status != OK) {
649 return status;
650 }
651 return processReturn("updateSourceMetadata", mStream->updateSourceMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -0700652}
Kevin Rocard070e7512018-05-22 09:29:13 -0700653#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700654
jiabinf6eb4c32020-02-25 14:06:25 -0800655#if MAJOR_VERSION < 6
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800656status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode __unused) {
657 return INVALID_OPERATION;
658}
659
660status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode __unused) {
661 return INVALID_OPERATION;
662}
663
664status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB __unused) {
665 return INVALID_OPERATION;
666}
667
668status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB __unused) {
669 return INVALID_OPERATION;
670}
671
672status_t StreamOutHalHidl::getPlaybackRateParameters(
673 audio_playback_rate_t* playbackRate __unused) {
674 return INVALID_OPERATION;
675}
676
677status_t StreamOutHalHidl::setPlaybackRateParameters(
678 const audio_playback_rate_t& playbackRate __unused) {
679 return INVALID_OPERATION;
680}
681
jiabinf6eb4c32020-02-25 14:06:25 -0800682status_t StreamOutHalHidl::setEventCallback(
683 const sp<StreamOutHalInterfaceEventCallback>& callback __unused) {
684 // Codec format callback is supported starting from audio HAL V6.0
685 return INVALID_OPERATION;
686}
687#else
688
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800689status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode) {
690 if (mStream == 0) return NO_INIT;
691 Result retval;
692 Return<void> ret = mStream->getDualMonoMode(
693 [&](Result r, DualMonoMode hidlMode) {
694 retval = r;
695 if (retval == Result::OK) {
696 *mode = static_cast<audio_dual_mono_mode_t>(hidlMode);
697 }
698 });
699 return processReturn("getDualMonoMode", ret, retval);
700}
701
702status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode) {
703 if (mStream == 0) return NO_INIT;
704 return processReturn(
705 "setDualMonoMode", mStream->setDualMonoMode(static_cast<DualMonoMode>(mode)));
706}
707
708status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB) {
709 if (mStream == 0) return NO_INIT;
710 Result retval;
711 Return<void> ret = mStream->getAudioDescriptionMixLevel(
712 [&](Result r, float hidlLeveldB) {
713 retval = r;
714 if (retval == Result::OK) {
715 *leveldB = hidlLeveldB;
716 }
717 });
718 return processReturn("getAudioDescriptionMixLevel", ret, retval);
719}
720
721status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB) {
722 if (mStream == 0) return NO_INIT;
723 return processReturn(
724 "setAudioDescriptionMixLevel", mStream->setAudioDescriptionMixLevel(leveldB));
725}
726
727status_t StreamOutHalHidl::getPlaybackRateParameters(audio_playback_rate_t* playbackRate) {
728 if (mStream == 0) return NO_INIT;
729 Result retval;
730 Return<void> ret = mStream->getPlaybackRateParameters(
731 [&](Result r, PlaybackRate hidlPlaybackRate) {
732 retval = r;
733 if (retval == Result::OK) {
734 playbackRate->mSpeed = hidlPlaybackRate.speed;
735 playbackRate->mPitch = hidlPlaybackRate.pitch;
736 playbackRate->mStretchMode =
737 static_cast<audio_timestretch_stretch_mode_t>(
738 hidlPlaybackRate.timestretchMode);
739 playbackRate->mFallbackMode =
740 static_cast<audio_timestretch_fallback_mode_t>(
741 hidlPlaybackRate.fallbackMode);
742 }
743 });
744 return processReturn("getPlaybackRateParameters", ret, retval);
745}
746
747status_t StreamOutHalHidl::setPlaybackRateParameters(const audio_playback_rate_t& playbackRate) {
748 if (mStream == 0) return NO_INIT;
749 return processReturn(
750 "setPlaybackRateParameters", mStream->setPlaybackRateParameters(
751 PlaybackRate{playbackRate.mSpeed, playbackRate.mPitch,
752 static_cast<TimestretchMode>(playbackRate.mStretchMode),
753 static_cast<TimestretchFallbackMode>(playbackRate.mFallbackMode)}));
754}
755
jiabinf6eb4c32020-02-25 14:06:25 -0800756#include PATH(android/hardware/audio/FILE_VERSION/IStreamOutEventCallback.h)
757
758namespace {
759
760struct StreamOutEventCallback : public IStreamOutEventCallback {
761 StreamOutEventCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
762
763 // IStreamOutEventCallback implementation
764 Return<void> onCodecFormatChanged(
765 const android::hardware::hidl_vec<uint8_t>& audioMetadata) override {
766 sp<StreamOutHalHidl> stream = mStream.promote();
767 if (stream != nullptr) {
768 std::basic_string<uint8_t> metadataBs(audioMetadata.begin(), audioMetadata.end());
769 stream->onCodecFormatChanged(metadataBs);
770 }
771 return Void();
772 }
773
774 private:
775 wp<StreamOutHalHidl> mStream;
776};
777
778} // namespace
779
780status_t StreamOutHalHidl::setEventCallback(
781 const sp<StreamOutHalInterfaceEventCallback>& callback) {
782 if (mStream == nullptr) return NO_INIT;
783 mEventCallback = callback;
784 status_t status = processReturn(
785 "setEventCallback",
786 mStream->setEventCallback(
787 callback.get() == nullptr ? nullptr : new StreamOutEventCallback(this)));
788 return status;
789}
790#endif
791
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800792void StreamOutHalHidl::onWriteReady() {
Andy Hung638f45b2021-01-18 20:02:56 -0800793 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800794 if (callback == 0) return;
795 ALOGV("asyncCallback onWriteReady");
796 callback->onWriteReady();
797}
798
799void StreamOutHalHidl::onDrainReady() {
Andy Hung638f45b2021-01-18 20:02:56 -0800800 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800801 if (callback == 0) return;
802 ALOGV("asyncCallback onDrainReady");
803 callback->onDrainReady();
804}
805
806void StreamOutHalHidl::onError() {
Andy Hung638f45b2021-01-18 20:02:56 -0800807 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800808 if (callback == 0) return;
809 ALOGV("asyncCallback onError");
810 callback->onError();
811}
812
jiabinf6eb4c32020-02-25 14:06:25 -0800813void StreamOutHalHidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) {
Andy Hung638f45b2021-01-18 20:02:56 -0800814 sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.load().promote();
jiabinf6eb4c32020-02-25 14:06:25 -0800815 if (callback == nullptr) return;
816 ALOGV("asyncCodecFormatCallback %s", __func__);
817 callback->onCodecFormatChanged(metadataBs);
818}
819
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800820
821StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
822 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
823}
824
825StreamInHalHidl::~StreamInHalHidl() {
826 if (mStream != 0) {
827 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800828 }
829 if (mEfGroup) {
830 EventFlag::deleteEventFlag(&mEfGroup);
831 }
832}
833
834status_t StreamInHalHidl::getFrameSize(size_t *size) {
835 if (mStream == 0) return NO_INIT;
836 return processReturn("getFrameSize", mStream->getFrameSize(), size);
837}
838
839status_t StreamInHalHidl::setGain(float gain) {
840 if (mStream == 0) return NO_INIT;
841 return processReturn("setGain", mStream->setGain(gain));
842}
843
844status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
845 if (mStream == 0) return NO_INIT;
846 *read = 0;
847
848 if (bytes == 0 && !mDataMQ) {
849 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
850 return OK;
851 }
852
853 status_t status;
854 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
855 return status;
856 }
857
858 ReadParameters params;
859 params.command = ReadCommand::READ;
860 params.params.read = bytes;
861 status = callReaderThread(params, "read",
862 [&](const ReadStatus& readStatus) {
863 const size_t availToRead = mDataMQ->availableToRead();
864 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
865 ALOGE("data message queue read failed for \"read\"");
866 }
867 ALOGW_IF(availToRead != readStatus.reply.read,
868 "HAL read report inconsistent: mq = %d, status = %d",
869 (int32_t)availToRead, (int32_t)readStatus.reply.read);
870 *read = readStatus.reply.read;
871 });
872 mStreamPowerLog.log(buffer, *read);
873 return status;
874}
875
876status_t StreamInHalHidl::callReaderThread(
877 const ReadParameters& params, const char* cmdName,
878 StreamInHalHidl::ReaderCallback callback) {
879 if (!mCommandMQ->write(&params)) {
880 ALOGW("command message queue write failed");
881 return -EAGAIN;
882 }
883 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
884
885 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
886 uint32_t efState = 0;
887retry:
888 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
889 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
890 ReadStatus readStatus;
891 readStatus.retval = Result::NOT_INITIALIZED;
892 if (!mStatusMQ->read(&readStatus)) {
893 ALOGE("status message read failed for \"%s\"", cmdName);
894 }
895 if (readStatus.retval == Result::OK) {
896 ret = OK;
897 callback(readStatus);
898 } else {
899 ret = processReturn(cmdName, readStatus.retval);
900 }
901 return ret;
902 }
903 if (ret == -EAGAIN || ret == -EINTR) {
904 // Spurious wakeup. This normally retries no more than once.
905 goto retry;
906 }
907 return ret;
908}
909
910status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
911 std::unique_ptr<CommandMQ> tempCommandMQ;
912 std::unique_ptr<DataMQ> tempDataMQ;
913 std::unique_ptr<StatusMQ> tempStatusMQ;
914 Result retval;
915 pid_t halThreadPid, halThreadTid;
916 Return<void> ret = mStream->prepareForReading(
917 1, bufferSize,
918 [&](Result r,
919 const CommandMQ::Descriptor& commandMQ,
920 const DataMQ::Descriptor& dataMQ,
921 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000922 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800923 retval = r;
924 if (retval == Result::OK) {
925 tempCommandMQ.reset(new CommandMQ(commandMQ));
926 tempDataMQ.reset(new DataMQ(dataMQ));
927 tempStatusMQ.reset(new StatusMQ(statusMQ));
928 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
929 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
930 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000931#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800932 halThreadPid = halThreadInfo.pid;
933 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000934#else
935 halThreadTid = halThreadInfo;
936#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800937 }
938 });
939 if (!ret.isOk() || retval != Result::OK) {
940 return processReturn("prepareForReading", ret, retval);
941 }
942 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
943 !tempDataMQ || !tempDataMQ->isValid() ||
944 !tempStatusMQ || !tempStatusMQ->isValid() ||
945 !mEfGroup) {
946 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
947 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
948 "Command message queue for writing is invalid");
949 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
950 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
951 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
952 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
953 "Status message queue for reading is invalid");
954 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
955 return NO_INIT;
956 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000957#if MAJOR_VERSION >= 7
958 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
959 return status;
960 }
961#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800962 requestHalThreadPriority(halThreadPid, halThreadTid);
963
964 mCommandMQ = std::move(tempCommandMQ);
965 mDataMQ = std::move(tempDataMQ);
966 mStatusMQ = std::move(tempStatusMQ);
967 mReaderClient = gettid();
968 return OK;
969}
970
971status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
972 if (mStream == 0) return NO_INIT;
973 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
974}
975
976status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
977 if (mStream == 0) return NO_INIT;
978 if (mReaderClient == gettid() && mCommandMQ) {
979 ReadParameters params;
980 params.command = ReadCommand::GET_CAPTURE_POSITION;
981 return callReaderThread(params, "getCapturePosition",
982 [&](const ReadStatus& readStatus) {
983 *frames = readStatus.reply.capturePosition.frames;
984 *time = readStatus.reply.capturePosition.time;
985 });
986 } else {
987 Result retval;
988 Return<void> ret = mStream->getCapturePosition(
989 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
990 retval = r;
991 if (retval == Result::OK) {
992 *frames = hidlFrames;
993 *time = hidlTime;
994 }
995 });
996 return processReturn("getCapturePosition", ret, retval);
997 }
998}
999
Kevin Rocard070e7512018-05-22 09:29:13 -07001000#if MAJOR_VERSION == 2
1001status_t StreamInHalHidl::getActiveMicrophones(
1002 std::vector<media::MicrophoneInfo> *microphones __unused) {
1003 if (mStream == 0) return NO_INIT;
1004 return INVALID_OPERATION;
1005}
1006
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001007status_t StreamInHalHidl::updateSinkMetadata(
1008 const StreamInHalInterface::SinkMetadata& /* sinkMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -07001009 // Audio HAL V2.0 does not support propagating sink metadata
1010 return INVALID_OPERATION;
1011}
1012
Kevin Rocard3d48dce2018-11-08 17:16:57 -08001013#elif MAJOR_VERSION >= 4
jiabin9ff780e2018-03-19 18:19:52 -07001014status_t StreamInHalHidl::getActiveMicrophones(
1015 std::vector<media::MicrophoneInfo> *microphonesInfo) {
1016 if (!mStream) return NO_INIT;
1017 Result retval;
1018 Return<void> ret = mStream->getActiveMicrophones(
1019 [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
1020 retval = r;
1021 for (size_t k = 0; k < micArrayHal.size(); k++) {
1022 audio_microphone_characteristic_t dst;
1023 // convert
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001024 (void)CoreUtils::microphoneInfoToHal(micArrayHal[k], &dst);
jiabin9ff780e2018-03-19 18:19:52 -07001025 media::MicrophoneInfo microphone = media::MicrophoneInfo(dst);
1026 microphonesInfo->push_back(microphone);
1027 }
1028 });
1029 return processReturn("getActiveMicrophones", ret, retval);
1030}
1031
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001032status_t StreamInHalHidl::updateSinkMetadata(const
1033 StreamInHalInterface::SinkMetadata& sinkMetadata) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001034 CPP_VERSION::SinkMetadata hidlMetadata;
1035 if (status_t status = CoreUtils::sinkMetadataFromHalV7(
1036 sinkMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
1037 status != OK) {
1038 return status;
1039 }
1040 return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -07001041}
Kevin Rocard070e7512018-05-22 09:29:13 -07001042#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -07001043
Paul McLean03a6e6a2018-12-04 10:54:13 -07001044#if MAJOR_VERSION < 5
Paul McLean12340082019-03-19 09:35:05 -06001045status_t StreamInHalHidl::setPreferredMicrophoneDirection(
1046 audio_microphone_direction_t direction __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001047 if (mStream == 0) return NO_INIT;
1048 return INVALID_OPERATION;
1049}
1050
Paul McLean12340082019-03-19 09:35:05 -06001051status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001052 if (mStream == 0) return NO_INIT;
1053 return INVALID_OPERATION;
1054}
1055#else
Paul McLean12340082019-03-19 09:35:05 -06001056status_t StreamInHalHidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001057 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001058 return processReturn("setPreferredMicrophoneDirection",
1059 mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction)));
Paul McLean03a6e6a2018-12-04 10:54:13 -07001060}
1061
Paul McLean12340082019-03-19 09:35:05 -06001062status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001063 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001064 return processReturn("setPreferredMicrophoneFieldDimension",
Paul McLean03a6e6a2018-12-04 10:54:13 -07001065 mStream->setMicrophoneFieldDimension(zoom));
1066}
1067#endif
1068
Kevin Rocard070e7512018-05-22 09:29:13 -07001069} // namespace CPP_VERSION
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001070} // namespace android