blob: 703d3024799f16f07567e54cc8cebf8d3a658b75 [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
274namespace {
275
276/* Notes on callback ownership.
277
278This is how (Hw)Binder ownership model looks like. The server implementation
279is owned by Binder framework (via sp<>). Proxies are owned by clients.
280When the last proxy disappears, Binder framework releases the server impl.
281
282Thus, it is not needed to keep any references to StreamOutCallback (this is
283the server impl) -- it will live as long as HAL server holds a strong ref to
284IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
285from the destructor of StreamOutHalHidl.
286
287The callback only keeps a weak reference to the stream. The stream is owned
288by AudioFlinger.
289
290*/
291
292struct StreamOutCallback : public IStreamOutCallback {
293 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
294
295 // IStreamOutCallback implementation
296 Return<void> onWriteReady() override {
297 sp<StreamOutHalHidl> stream = mStream.promote();
298 if (stream != 0) {
299 stream->onWriteReady();
300 }
301 return Void();
302 }
303
304 Return<void> onDrainReady() override {
305 sp<StreamOutHalHidl> stream = mStream.promote();
306 if (stream != 0) {
307 stream->onDrainReady();
308 }
309 return Void();
310 }
311
312 Return<void> onError() override {
313 sp<StreamOutHalHidl> stream = mStream.promote();
314 if (stream != 0) {
315 stream->onError();
316 }
317 return Void();
318 }
319
320 private:
Andy Hung638f45b2021-01-18 20:02:56 -0800321 const wp<StreamOutHalHidl> mStream;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800322};
323
324} // namespace
325
Mikhail Naganov6718c392022-01-27 22:17:21 +0000326StreamOutHalHidl::StreamOutHalHidl(
327 const sp<::android::hardware::audio::CPP_VERSION::IStreamOut>& stream)
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800328 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
329}
330
331StreamOutHalHidl::~StreamOutHalHidl() {
332 if (mStream != 0) {
Andy Hung638f45b2021-01-18 20:02:56 -0800333 if (mCallback.load().unsafe_get()) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800334 processReturn("clearCallback", mStream->clearCallback());
335 }
jiabinf6eb4c32020-02-25 14:06:25 -0800336#if MAJOR_VERSION >= 6
Andy Hung638f45b2021-01-18 20:02:56 -0800337 if (mEventCallback.load().unsafe_get() != nullptr) {
jiabinf6eb4c32020-02-25 14:06:25 -0800338 processReturn("setEventCallback",
339 mStream->setEventCallback(nullptr));
340 }
341#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800342 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800343 }
Andy Hung638f45b2021-01-18 20:02:56 -0800344 mCallback = nullptr;
345 mEventCallback = nullptr;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800346 if (mEfGroup) {
347 EventFlag::deleteEventFlag(&mEfGroup);
348 }
349}
350
351status_t StreamOutHalHidl::getFrameSize(size_t *size) {
352 if (mStream == 0) return NO_INIT;
353 return processReturn("getFrameSize", mStream->getFrameSize(), size);
354}
355
356status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
357 if (mStream == 0) return NO_INIT;
358 if (mWriterClient == gettid() && mCommandMQ) {
359 return callWriterThread(
360 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
361 [&](const WriteStatus& writeStatus) {
362 *latency = writeStatus.reply.latencyMs;
363 });
364 } else {
365 return processReturn("getLatency", mStream->getLatency(), latency);
366 }
367}
368
369status_t StreamOutHalHidl::setVolume(float left, float right) {
370 if (mStream == 0) return NO_INIT;
371 return processReturn("setVolume", mStream->setVolume(left, right));
372}
373
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800374#if MAJOR_VERSION == 2
375status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
376 if (mStream == 0) return NO_INIT;
377 std::vector<ParameterValue> parameters;
378 String8 halParameters;
379 parameters.push_back({AudioParameter::keyPresentationId, std::to_string(presentationId)});
380 parameters.push_back({AudioParameter::keyProgramId, std::to_string(programId)});
381 parametersToHal(hidl_vec<ParameterValue>(parameters), &halParameters);
382 return setParameters(halParameters);
383}
Kevin Rocard1cf6b4d2018-11-20 18:05:44 -0800384#elif MAJOR_VERSION >= 4
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800385status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
386 if (mStream == 0) return NO_INIT;
387 return processReturn("selectPresentation",
388 mStream->selectPresentation(presentationId, programId));
389}
390#endif
391
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800392status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
393 if (mStream == 0) return NO_INIT;
394 *written = 0;
395
396 if (bytes == 0 && !mDataMQ) {
397 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
Andy Hung638f45b2021-01-18 20:02:56 -0800398 ALOGW_IF(mCallback.load().unsafe_get(), "First call to async write with 0 bytes");
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800399 return OK;
400 }
401
402 status_t status;
403 if (!mDataMQ) {
404 // In case if playback starts close to the end of a compressed track, the bytes
405 // that need to be written is less than the actual buffer size. Need to use
406 // full buffer size for the MQ since otherwise after seeking back to the middle
407 // data will be truncated.
408 size_t bufferSize;
409 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
410 return status;
411 }
412 if (bytes > bufferSize) bufferSize = bytes;
413 if ((status = prepareForWriting(bufferSize)) != OK) {
414 return status;
415 }
416 }
417
418 status = callWriterThread(
419 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
420 [&] (const WriteStatus& writeStatus) {
421 *written = writeStatus.reply.written;
422 // Diagnostics of the cause of b/35813113.
423 ALOGE_IF(*written > bytes,
424 "hal reports more bytes written than asked for: %lld > %lld",
425 (long long)*written, (long long)bytes);
426 });
427 mStreamPowerLog.log(buffer, *written);
428 return status;
429}
430
431status_t StreamOutHalHidl::callWriterThread(
432 WriteCommand cmd, const char* cmdName,
433 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
434 if (!mCommandMQ->write(&cmd)) {
435 ALOGE("command message queue write failed for \"%s\"", cmdName);
436 return -EAGAIN;
437 }
438 if (data != nullptr) {
439 size_t availableToWrite = mDataMQ->availableToWrite();
440 if (dataSize > availableToWrite) {
441 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
442 (long long)dataSize, (long long)availableToWrite);
443 dataSize = availableToWrite;
444 }
445 if (!mDataMQ->write(data, dataSize)) {
446 ALOGE("data message queue write failed for \"%s\"", cmdName);
447 }
448 }
449 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
450
451 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
452 uint32_t efState = 0;
453retry:
454 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
455 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
456 WriteStatus writeStatus;
457 writeStatus.retval = Result::NOT_INITIALIZED;
458 if (!mStatusMQ->read(&writeStatus)) {
459 ALOGE("status message read failed for \"%s\"", cmdName);
460 }
461 if (writeStatus.retval == Result::OK) {
462 ret = OK;
463 callback(writeStatus);
464 } else {
465 ret = processReturn(cmdName, writeStatus.retval);
466 }
467 return ret;
468 }
469 if (ret == -EAGAIN || ret == -EINTR) {
470 // Spurious wakeup. This normally retries no more than once.
471 goto retry;
472 }
473 return ret;
474}
475
476status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
477 std::unique_ptr<CommandMQ> tempCommandMQ;
478 std::unique_ptr<DataMQ> tempDataMQ;
479 std::unique_ptr<StatusMQ> tempStatusMQ;
480 Result retval;
481 pid_t halThreadPid, halThreadTid;
482 Return<void> ret = mStream->prepareForWriting(
483 1, bufferSize,
484 [&](Result r,
485 const CommandMQ::Descriptor& commandMQ,
486 const DataMQ::Descriptor& dataMQ,
487 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000488 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800489 retval = r;
490 if (retval == Result::OK) {
491 tempCommandMQ.reset(new CommandMQ(commandMQ));
492 tempDataMQ.reset(new DataMQ(dataMQ));
493 tempStatusMQ.reset(new StatusMQ(statusMQ));
494 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
495 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
496 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000497#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800498 halThreadPid = halThreadInfo.pid;
499 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000500#else
501 halThreadTid = halThreadInfo;
502#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800503 }
504 });
505 if (!ret.isOk() || retval != Result::OK) {
506 return processReturn("prepareForWriting", ret, retval);
507 }
508 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
509 !tempDataMQ || !tempDataMQ->isValid() ||
510 !tempStatusMQ || !tempStatusMQ->isValid() ||
511 !mEfGroup) {
512 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
513 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
514 "Command message queue for writing is invalid");
515 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
516 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
517 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
518 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
519 "Status message queue for writing is invalid");
520 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
521 return NO_INIT;
522 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000523#if MAJOR_VERSION >= 7
524 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
525 return status;
526 }
527#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800528 requestHalThreadPriority(halThreadPid, halThreadTid);
529
530 mCommandMQ = std::move(tempCommandMQ);
531 mDataMQ = std::move(tempDataMQ);
532 mStatusMQ = std::move(tempStatusMQ);
533 mWriterClient = gettid();
534 return OK;
535}
536
537status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
538 if (mStream == 0) return NO_INIT;
539 Result retval;
540 Return<void> ret = mStream->getRenderPosition(
541 [&](Result r, uint32_t d) {
542 retval = r;
543 if (retval == Result::OK) {
544 *dspFrames = d;
545 }
546 });
547 return processReturn("getRenderPosition", ret, retval);
548}
549
550status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
551 if (mStream == 0) return NO_INIT;
552 Result retval;
553 Return<void> ret = mStream->getNextWriteTimestamp(
554 [&](Result r, int64_t t) {
555 retval = r;
556 if (retval == Result::OK) {
557 *timestamp = t;
558 }
559 });
560 return processReturn("getRenderPosition", ret, retval);
561}
562
563status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
564 if (mStream == 0) return NO_INIT;
565 status_t status = processReturn(
566 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
567 if (status == OK) {
568 mCallback = callback;
569 }
570 return status;
571}
572
573status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
574 if (mStream == 0) return NO_INIT;
575 Return<void> ret = mStream->supportsPauseAndResume(
576 [&](bool p, bool r) {
577 *supportsPause = p;
578 *supportsResume = r;
579 });
580 return processReturn("supportsPauseAndResume", ret);
581}
582
583status_t StreamOutHalHidl::pause() {
584 if (mStream == 0) return NO_INIT;
585 return processReturn("pause", mStream->pause());
586}
587
588status_t StreamOutHalHidl::resume() {
589 if (mStream == 0) return NO_INIT;
590 return processReturn("pause", mStream->resume());
591}
592
593status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
594 if (mStream == 0) return NO_INIT;
595 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
596}
597
598status_t StreamOutHalHidl::drain(bool earlyNotify) {
599 if (mStream == 0) return NO_INIT;
600 return processReturn(
601 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
602}
603
604status_t StreamOutHalHidl::flush() {
605 if (mStream == 0) return NO_INIT;
606 return processReturn("pause", mStream->flush());
607}
608
609status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
610 if (mStream == 0) return NO_INIT;
611 if (mWriterClient == gettid() && mCommandMQ) {
612 return callWriterThread(
613 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
614 [&](const WriteStatus& writeStatus) {
615 *frames = writeStatus.reply.presentationPosition.frames;
616 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
617 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
618 });
619 } else {
620 Result retval;
621 Return<void> ret = mStream->getPresentationPosition(
622 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
623 retval = r;
624 if (retval == Result::OK) {
625 *frames = hidlFrames;
626 timestamp->tv_sec = hidlTimeStamp.tvSec;
627 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
628 }
629 });
630 return processReturn("getPresentationPosition", ret, retval);
631 }
632}
633
Kevin Rocard070e7512018-05-22 09:29:13 -0700634#if MAJOR_VERSION == 2
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800635status_t StreamOutHalHidl::updateSourceMetadata(
636 const StreamOutHalInterface::SourceMetadata& /* sourceMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700637 // Audio HAL V2.0 does not support propagating source metadata
638 return INVALID_OPERATION;
639}
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800640#elif MAJOR_VERSION >= 4
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800641status_t StreamOutHalHidl::updateSourceMetadata(
642 const StreamOutHalInterface::SourceMetadata& sourceMetadata) {
Mikhail Naganov6718c392022-01-27 22:17:21 +0000643#if MAJOR_VERSION == 4
644 ::android::hardware::audio::CORE_TYPES_CPP_VERSION::SourceMetadata hidlMetadata;
645#else
646 ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::SourceMetadata hidlMetadata;
647#endif
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000648 if (status_t status = CoreUtils::sourceMetadataFromHalV7(
649 sourceMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
650 status != OK) {
651 return status;
652 }
653 return processReturn("updateSourceMetadata", mStream->updateSourceMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -0700654}
Kevin Rocard070e7512018-05-22 09:29:13 -0700655#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700656
jiabinf6eb4c32020-02-25 14:06:25 -0800657#if MAJOR_VERSION < 6
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800658status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode __unused) {
659 return INVALID_OPERATION;
660}
661
662status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode __unused) {
663 return INVALID_OPERATION;
664}
665
666status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB __unused) {
667 return INVALID_OPERATION;
668}
669
670status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB __unused) {
671 return INVALID_OPERATION;
672}
673
674status_t StreamOutHalHidl::getPlaybackRateParameters(
675 audio_playback_rate_t* playbackRate __unused) {
676 return INVALID_OPERATION;
677}
678
679status_t StreamOutHalHidl::setPlaybackRateParameters(
680 const audio_playback_rate_t& playbackRate __unused) {
681 return INVALID_OPERATION;
682}
683
jiabinf6eb4c32020-02-25 14:06:25 -0800684status_t StreamOutHalHidl::setEventCallback(
685 const sp<StreamOutHalInterfaceEventCallback>& callback __unused) {
686 // Codec format callback is supported starting from audio HAL V6.0
687 return INVALID_OPERATION;
688}
689#else
690
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800691status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode) {
692 if (mStream == 0) return NO_INIT;
693 Result retval;
694 Return<void> ret = mStream->getDualMonoMode(
695 [&](Result r, DualMonoMode hidlMode) {
696 retval = r;
697 if (retval == Result::OK) {
698 *mode = static_cast<audio_dual_mono_mode_t>(hidlMode);
699 }
700 });
701 return processReturn("getDualMonoMode", ret, retval);
702}
703
704status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode) {
705 if (mStream == 0) return NO_INIT;
706 return processReturn(
707 "setDualMonoMode", mStream->setDualMonoMode(static_cast<DualMonoMode>(mode)));
708}
709
710status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB) {
711 if (mStream == 0) return NO_INIT;
712 Result retval;
713 Return<void> ret = mStream->getAudioDescriptionMixLevel(
714 [&](Result r, float hidlLeveldB) {
715 retval = r;
716 if (retval == Result::OK) {
717 *leveldB = hidlLeveldB;
718 }
719 });
720 return processReturn("getAudioDescriptionMixLevel", ret, retval);
721}
722
723status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB) {
724 if (mStream == 0) return NO_INIT;
725 return processReturn(
726 "setAudioDescriptionMixLevel", mStream->setAudioDescriptionMixLevel(leveldB));
727}
728
729status_t StreamOutHalHidl::getPlaybackRateParameters(audio_playback_rate_t* playbackRate) {
730 if (mStream == 0) return NO_INIT;
731 Result retval;
732 Return<void> ret = mStream->getPlaybackRateParameters(
733 [&](Result r, PlaybackRate hidlPlaybackRate) {
734 retval = r;
735 if (retval == Result::OK) {
736 playbackRate->mSpeed = hidlPlaybackRate.speed;
737 playbackRate->mPitch = hidlPlaybackRate.pitch;
738 playbackRate->mStretchMode =
739 static_cast<audio_timestretch_stretch_mode_t>(
740 hidlPlaybackRate.timestretchMode);
741 playbackRate->mFallbackMode =
742 static_cast<audio_timestretch_fallback_mode_t>(
743 hidlPlaybackRate.fallbackMode);
744 }
745 });
746 return processReturn("getPlaybackRateParameters", ret, retval);
747}
748
749status_t StreamOutHalHidl::setPlaybackRateParameters(const audio_playback_rate_t& playbackRate) {
750 if (mStream == 0) return NO_INIT;
751 return processReturn(
752 "setPlaybackRateParameters", mStream->setPlaybackRateParameters(
753 PlaybackRate{playbackRate.mSpeed, playbackRate.mPitch,
754 static_cast<TimestretchMode>(playbackRate.mStretchMode),
755 static_cast<TimestretchFallbackMode>(playbackRate.mFallbackMode)}));
756}
757
Mikhail Naganov6718c392022-01-27 22:17:21 +0000758#include PATH(android/hardware/audio/CORE_TYPES_FILE_VERSION/IStreamOutEventCallback.h)
jiabinf6eb4c32020-02-25 14:06:25 -0800759
760namespace {
761
762struct StreamOutEventCallback : public IStreamOutEventCallback {
763 StreamOutEventCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
764
765 // IStreamOutEventCallback implementation
766 Return<void> onCodecFormatChanged(
767 const android::hardware::hidl_vec<uint8_t>& audioMetadata) override {
768 sp<StreamOutHalHidl> stream = mStream.promote();
769 if (stream != nullptr) {
770 std::basic_string<uint8_t> metadataBs(audioMetadata.begin(), audioMetadata.end());
771 stream->onCodecFormatChanged(metadataBs);
772 }
773 return Void();
774 }
775
776 private:
777 wp<StreamOutHalHidl> mStream;
778};
779
780} // namespace
781
782status_t StreamOutHalHidl::setEventCallback(
783 const sp<StreamOutHalInterfaceEventCallback>& callback) {
784 if (mStream == nullptr) return NO_INIT;
785 mEventCallback = callback;
786 status_t status = processReturn(
787 "setEventCallback",
788 mStream->setEventCallback(
789 callback.get() == nullptr ? nullptr : new StreamOutEventCallback(this)));
790 return status;
791}
792#endif
793
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800794void StreamOutHalHidl::onWriteReady() {
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 onWriteReady");
798 callback->onWriteReady();
799}
800
801void StreamOutHalHidl::onDrainReady() {
Andy Hung638f45b2021-01-18 20:02:56 -0800802 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800803 if (callback == 0) return;
804 ALOGV("asyncCallback onDrainReady");
805 callback->onDrainReady();
806}
807
808void StreamOutHalHidl::onError() {
Andy Hung638f45b2021-01-18 20:02:56 -0800809 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800810 if (callback == 0) return;
811 ALOGV("asyncCallback onError");
812 callback->onError();
813}
814
jiabinf6eb4c32020-02-25 14:06:25 -0800815void StreamOutHalHidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) {
Andy Hung638f45b2021-01-18 20:02:56 -0800816 sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.load().promote();
jiabinf6eb4c32020-02-25 14:06:25 -0800817 if (callback == nullptr) return;
818 ALOGV("asyncCodecFormatCallback %s", __func__);
819 callback->onCodecFormatChanged(metadataBs);
820}
821
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800822
Mikhail Naganov6718c392022-01-27 22:17:21 +0000823StreamInHalHidl::StreamInHalHidl(
824 const sp<::android::hardware::audio::CPP_VERSION::IStreamIn>& stream)
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800825 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
826}
827
828StreamInHalHidl::~StreamInHalHidl() {
829 if (mStream != 0) {
830 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800831 }
832 if (mEfGroup) {
833 EventFlag::deleteEventFlag(&mEfGroup);
834 }
835}
836
837status_t StreamInHalHidl::getFrameSize(size_t *size) {
838 if (mStream == 0) return NO_INIT;
839 return processReturn("getFrameSize", mStream->getFrameSize(), size);
840}
841
842status_t StreamInHalHidl::setGain(float gain) {
843 if (mStream == 0) return NO_INIT;
844 return processReturn("setGain", mStream->setGain(gain));
845}
846
847status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
848 if (mStream == 0) return NO_INIT;
849 *read = 0;
850
851 if (bytes == 0 && !mDataMQ) {
852 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
853 return OK;
854 }
855
856 status_t status;
857 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
858 return status;
859 }
860
861 ReadParameters params;
862 params.command = ReadCommand::READ;
863 params.params.read = bytes;
864 status = callReaderThread(params, "read",
865 [&](const ReadStatus& readStatus) {
866 const size_t availToRead = mDataMQ->availableToRead();
867 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
868 ALOGE("data message queue read failed for \"read\"");
869 }
870 ALOGW_IF(availToRead != readStatus.reply.read,
871 "HAL read report inconsistent: mq = %d, status = %d",
872 (int32_t)availToRead, (int32_t)readStatus.reply.read);
873 *read = readStatus.reply.read;
874 });
875 mStreamPowerLog.log(buffer, *read);
876 return status;
877}
878
879status_t StreamInHalHidl::callReaderThread(
880 const ReadParameters& params, const char* cmdName,
881 StreamInHalHidl::ReaderCallback callback) {
882 if (!mCommandMQ->write(&params)) {
883 ALOGW("command message queue write failed");
884 return -EAGAIN;
885 }
886 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
887
888 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
889 uint32_t efState = 0;
890retry:
891 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
892 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
893 ReadStatus readStatus;
894 readStatus.retval = Result::NOT_INITIALIZED;
895 if (!mStatusMQ->read(&readStatus)) {
896 ALOGE("status message read failed for \"%s\"", cmdName);
897 }
898 if (readStatus.retval == Result::OK) {
899 ret = OK;
900 callback(readStatus);
901 } else {
902 ret = processReturn(cmdName, readStatus.retval);
903 }
904 return ret;
905 }
906 if (ret == -EAGAIN || ret == -EINTR) {
907 // Spurious wakeup. This normally retries no more than once.
908 goto retry;
909 }
910 return ret;
911}
912
913status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
914 std::unique_ptr<CommandMQ> tempCommandMQ;
915 std::unique_ptr<DataMQ> tempDataMQ;
916 std::unique_ptr<StatusMQ> tempStatusMQ;
917 Result retval;
918 pid_t halThreadPid, halThreadTid;
919 Return<void> ret = mStream->prepareForReading(
920 1, bufferSize,
921 [&](Result r,
922 const CommandMQ::Descriptor& commandMQ,
923 const DataMQ::Descriptor& dataMQ,
924 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000925 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800926 retval = r;
927 if (retval == Result::OK) {
928 tempCommandMQ.reset(new CommandMQ(commandMQ));
929 tempDataMQ.reset(new DataMQ(dataMQ));
930 tempStatusMQ.reset(new StatusMQ(statusMQ));
931 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
932 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
933 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000934#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800935 halThreadPid = halThreadInfo.pid;
936 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000937#else
938 halThreadTid = halThreadInfo;
939#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800940 }
941 });
942 if (!ret.isOk() || retval != Result::OK) {
943 return processReturn("prepareForReading", ret, retval);
944 }
945 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
946 !tempDataMQ || !tempDataMQ->isValid() ||
947 !tempStatusMQ || !tempStatusMQ->isValid() ||
948 !mEfGroup) {
949 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
950 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
951 "Command message queue for writing is invalid");
952 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
953 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
954 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
955 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
956 "Status message queue for reading is invalid");
957 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
958 return NO_INIT;
959 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000960#if MAJOR_VERSION >= 7
961 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
962 return status;
963 }
964#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800965 requestHalThreadPriority(halThreadPid, halThreadTid);
966
967 mCommandMQ = std::move(tempCommandMQ);
968 mDataMQ = std::move(tempDataMQ);
969 mStatusMQ = std::move(tempStatusMQ);
970 mReaderClient = gettid();
971 return OK;
972}
973
974status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
975 if (mStream == 0) return NO_INIT;
976 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
977}
978
979status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
980 if (mStream == 0) return NO_INIT;
981 if (mReaderClient == gettid() && mCommandMQ) {
982 ReadParameters params;
983 params.command = ReadCommand::GET_CAPTURE_POSITION;
984 return callReaderThread(params, "getCapturePosition",
985 [&](const ReadStatus& readStatus) {
986 *frames = readStatus.reply.capturePosition.frames;
987 *time = readStatus.reply.capturePosition.time;
988 });
989 } else {
990 Result retval;
991 Return<void> ret = mStream->getCapturePosition(
992 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
993 retval = r;
994 if (retval == Result::OK) {
995 *frames = hidlFrames;
996 *time = hidlTime;
997 }
998 });
999 return processReturn("getCapturePosition", ret, retval);
1000 }
1001}
1002
Kevin Rocard070e7512018-05-22 09:29:13 -07001003#if MAJOR_VERSION == 2
1004status_t StreamInHalHidl::getActiveMicrophones(
1005 std::vector<media::MicrophoneInfo> *microphones __unused) {
1006 if (mStream == 0) return NO_INIT;
1007 return INVALID_OPERATION;
1008}
1009
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001010status_t StreamInHalHidl::updateSinkMetadata(
1011 const StreamInHalInterface::SinkMetadata& /* sinkMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -07001012 // Audio HAL V2.0 does not support propagating sink metadata
1013 return INVALID_OPERATION;
1014}
1015
Kevin Rocard3d48dce2018-11-08 17:16:57 -08001016#elif MAJOR_VERSION >= 4
jiabin9ff780e2018-03-19 18:19:52 -07001017status_t StreamInHalHidl::getActiveMicrophones(
1018 std::vector<media::MicrophoneInfo> *microphonesInfo) {
1019 if (!mStream) return NO_INIT;
1020 Result retval;
1021 Return<void> ret = mStream->getActiveMicrophones(
1022 [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
1023 retval = r;
1024 for (size_t k = 0; k < micArrayHal.size(); k++) {
1025 audio_microphone_characteristic_t dst;
1026 // convert
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001027 (void)CoreUtils::microphoneInfoToHal(micArrayHal[k], &dst);
jiabin9ff780e2018-03-19 18:19:52 -07001028 media::MicrophoneInfo microphone = media::MicrophoneInfo(dst);
1029 microphonesInfo->push_back(microphone);
1030 }
1031 });
1032 return processReturn("getActiveMicrophones", ret, retval);
1033}
1034
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001035status_t StreamInHalHidl::updateSinkMetadata(const
1036 StreamInHalInterface::SinkMetadata& sinkMetadata) {
Mikhail Naganov6718c392022-01-27 22:17:21 +00001037#if MAJOR_VERSION == 4
1038 ::android::hardware::audio::CORE_TYPES_CPP_VERSION::SinkMetadata hidlMetadata;
1039#else
1040 ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::SinkMetadata hidlMetadata;
1041#endif
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001042 if (status_t status = CoreUtils::sinkMetadataFromHalV7(
1043 sinkMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
1044 status != OK) {
1045 return status;
1046 }
1047 return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -07001048}
Kevin Rocard070e7512018-05-22 09:29:13 -07001049#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -07001050
Paul McLean03a6e6a2018-12-04 10:54:13 -07001051#if MAJOR_VERSION < 5
Paul McLean12340082019-03-19 09:35:05 -06001052status_t StreamInHalHidl::setPreferredMicrophoneDirection(
1053 audio_microphone_direction_t direction __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001054 if (mStream == 0) return NO_INIT;
1055 return INVALID_OPERATION;
1056}
1057
Paul McLean12340082019-03-19 09:35:05 -06001058status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001059 if (mStream == 0) return NO_INIT;
1060 return INVALID_OPERATION;
1061}
1062#else
Paul McLean12340082019-03-19 09:35:05 -06001063status_t StreamInHalHidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001064 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001065 return processReturn("setPreferredMicrophoneDirection",
1066 mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction)));
Paul McLean03a6e6a2018-12-04 10:54:13 -07001067}
1068
Paul McLean12340082019-03-19 09:35:05 -06001069status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001070 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001071 return processReturn("setPreferredMicrophoneFieldDimension",
Paul McLean03a6e6a2018-12-04 10:54:13 -07001072 mStream->setMicrophoneFieldDimension(zoom));
1073}
1074#endif
1075
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001076} // namespace android