blob: 13001bc05da0178630210a92932e16af8058b049 [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 Naganovea1f19d2022-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 Naganovea1f19d2022-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 Naganovea1f19d2022-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 Naganovea1f19d2022-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 Naganovea1f19d2022-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
150status_t StreamHalHidl::dump(int fd) {
151 if (!mStream) return NO_INIT;
152 native_handle_t* hidlHandle = native_handle_create(1, 0);
153 hidlHandle->data[0] = fd;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800154 Return<void> ret = mStream->debug(hidlHandle, {} /* options */);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800155 native_handle_delete(hidlHandle);
Andy Hunge72ff022021-08-16 10:16:15 -0700156
157 // TODO(b/111997867, b/177271958) Workaround - remove when fixed.
158 // A Binder transmitted fd may not close immediately due to a race condition b/111997867
159 // when the remote binder thread removes the last refcount to the fd blocks in the
160 // kernel for binder activity. We send a Binder ping() command to unblock the thread
161 // and complete the fd close / release.
162 //
163 // See DeviceHalHidl::dump(), EffectHalHidl::dump(), StreamHalHidl::dump(),
164 // EffectsFactoryHalHidl::dumpEffects().
165
166 (void)mStream->ping(); // synchronous Binder call
167
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800168 mStreamPowerLog.dump(fd);
169 return processReturn("dump", ret);
170}
171
172status_t StreamHalHidl::start() {
173 if (!mStream) return NO_INIT;
174 return processReturn("start", mStream->start());
175}
176
177status_t StreamHalHidl::stop() {
178 if (!mStream) return NO_INIT;
179 return processReturn("stop", mStream->stop());
180}
181
182status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
183 struct audio_mmap_buffer_info *info) {
184 Result retval;
185 Return<void> ret = mStream->createMmapBuffer(
186 minSizeFrames,
187 [&](Result r, const MmapBufferInfo& hidlInfo) {
188 retval = r;
189 if (retval == Result::OK) {
190 const native_handle *handle = hidlInfo.sharedMemory.handle();
191 if (handle->numFds > 0) {
192 info->shared_memory_fd = handle->data[0];
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800193#if MAJOR_VERSION >= 4
Kevin Rocard734334f2018-07-12 19:37:41 -0700194 info->flags = audio_mmap_buffer_flag(hidlInfo.flags);
195#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800196 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
Kevin Rocard734334f2018-07-12 19:37:41 -0700197 // Negative buffer size frame was a hack in O and P to
198 // indicate that the buffer is shareable to applications
199 if (info->buffer_size_frames < 0) {
200 info->buffer_size_frames *= -1;
201 info->flags = audio_mmap_buffer_flag(
202 info->flags | AUDIO_MMAP_APPLICATION_SHAREABLE);
203 }
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800204 info->burst_size_frames = hidlInfo.burstSizeFrames;
205 // info->shared_memory_address is not needed in HIDL context
206 info->shared_memory_address = NULL;
207 } else {
208 retval = Result::NOT_INITIALIZED;
209 }
210 }
211 });
212 return processReturn("createMmapBuffer", ret, retval);
213}
214
215status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
216 Result retval;
217 Return<void> ret = mStream->getMmapPosition(
218 [&](Result r, const MmapPosition& hidlPosition) {
219 retval = r;
220 if (retval == Result::OK) {
221 position->time_nanoseconds = hidlPosition.timeNanoseconds;
222 position->position_frames = hidlPosition.positionFrames;
223 }
224 });
225 return processReturn("getMmapPosition", ret, retval);
226}
227
228status_t StreamHalHidl::setHalThreadPriority(int priority) {
229 mHalThreadPriority = priority;
230 return OK;
231}
232
233status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
234 if (mCachedBufferSize != 0) {
235 *size = mCachedBufferSize;
236 return OK;
237 }
238 return getBufferSize(size);
239}
240
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000241status_t StreamHalHidl::getHalPid(pid_t *pid) {
242 using ::android::hidl::base::V1_0::DebugInfo;
243 using ::android::hidl::manager::V1_0::IServiceManager;
244
245 DebugInfo debugInfo;
246 auto ret = mStream->getDebugInfo([&] (const auto &info) {
247 debugInfo = info;
248 });
249 if (!ret.isOk()) {
250 return INVALID_OPERATION;
251 }
252 if (debugInfo.pid != (int)IServiceManager::PidConstant::NO_PID) {
253 *pid = debugInfo.pid;
254 return NO_ERROR;
255 }
256 return NAME_NOT_FOUND;
257}
258
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800259bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
260 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
261 return true;
262 }
263 int err = requestPriority(
264 threadPid, threadId,
265 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
266 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
267 mHalThreadPriority, threadPid, threadId, err);
268 // Audio will still work, but latency will be higher and sometimes unacceptable.
269 return err == 0;
270}
271
272namespace {
273
274/* Notes on callback ownership.
275
276This is how (Hw)Binder ownership model looks like. The server implementation
277is owned by Binder framework (via sp<>). Proxies are owned by clients.
278When the last proxy disappears, Binder framework releases the server impl.
279
280Thus, it is not needed to keep any references to StreamOutCallback (this is
281the server impl) -- it will live as long as HAL server holds a strong ref to
282IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
283from the destructor of StreamOutHalHidl.
284
285The callback only keeps a weak reference to the stream. The stream is owned
286by AudioFlinger.
287
288*/
289
290struct StreamOutCallback : public IStreamOutCallback {
291 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
292
293 // IStreamOutCallback implementation
294 Return<void> onWriteReady() override {
295 sp<StreamOutHalHidl> stream = mStream.promote();
296 if (stream != 0) {
297 stream->onWriteReady();
298 }
299 return Void();
300 }
301
302 Return<void> onDrainReady() override {
303 sp<StreamOutHalHidl> stream = mStream.promote();
304 if (stream != 0) {
305 stream->onDrainReady();
306 }
307 return Void();
308 }
309
310 Return<void> onError() override {
311 sp<StreamOutHalHidl> stream = mStream.promote();
312 if (stream != 0) {
313 stream->onError();
314 }
315 return Void();
316 }
317
318 private:
Andy Hung638f45b2021-01-18 20:02:56 -0800319 const wp<StreamOutHalHidl> mStream;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800320};
321
322} // namespace
323
Mikhail Naganovea1f19d2022-01-27 22:17:21 +0000324StreamOutHalHidl::StreamOutHalHidl(
325 const sp<::android::hardware::audio::CPP_VERSION::IStreamOut>& stream)
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800326 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
327}
328
329StreamOutHalHidl::~StreamOutHalHidl() {
330 if (mStream != 0) {
Andy Hung638f45b2021-01-18 20:02:56 -0800331 if (mCallback.load().unsafe_get()) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800332 processReturn("clearCallback", mStream->clearCallback());
333 }
jiabinf6eb4c32020-02-25 14:06:25 -0800334#if MAJOR_VERSION >= 6
Andy Hung638f45b2021-01-18 20:02:56 -0800335 if (mEventCallback.load().unsafe_get() != nullptr) {
jiabinf6eb4c32020-02-25 14:06:25 -0800336 processReturn("setEventCallback",
337 mStream->setEventCallback(nullptr));
338 }
339#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800340 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800341 }
Andy Hung638f45b2021-01-18 20:02:56 -0800342 mCallback = nullptr;
343 mEventCallback = nullptr;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800344 if (mEfGroup) {
345 EventFlag::deleteEventFlag(&mEfGroup);
346 }
347}
348
349status_t StreamOutHalHidl::getFrameSize(size_t *size) {
350 if (mStream == 0) return NO_INIT;
351 return processReturn("getFrameSize", mStream->getFrameSize(), size);
352}
353
354status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
355 if (mStream == 0) return NO_INIT;
356 if (mWriterClient == gettid() && mCommandMQ) {
357 return callWriterThread(
358 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
359 [&](const WriteStatus& writeStatus) {
360 *latency = writeStatus.reply.latencyMs;
361 });
362 } else {
363 return processReturn("getLatency", mStream->getLatency(), latency);
364 }
365}
366
367status_t StreamOutHalHidl::setVolume(float left, float right) {
368 if (mStream == 0) return NO_INIT;
369 return processReturn("setVolume", mStream->setVolume(left, right));
370}
371
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800372#if MAJOR_VERSION == 2
373status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
374 if (mStream == 0) return NO_INIT;
375 std::vector<ParameterValue> parameters;
376 String8 halParameters;
377 parameters.push_back({AudioParameter::keyPresentationId, std::to_string(presentationId)});
378 parameters.push_back({AudioParameter::keyProgramId, std::to_string(programId)});
379 parametersToHal(hidl_vec<ParameterValue>(parameters), &halParameters);
380 return setParameters(halParameters);
381}
Kevin Rocard1cf6b4d2018-11-20 18:05:44 -0800382#elif MAJOR_VERSION >= 4
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800383status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
384 if (mStream == 0) return NO_INIT;
385 return processReturn("selectPresentation",
386 mStream->selectPresentation(presentationId, programId));
387}
388#endif
389
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800390status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
391 if (mStream == 0) return NO_INIT;
392 *written = 0;
393
394 if (bytes == 0 && !mDataMQ) {
395 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
Andy Hung638f45b2021-01-18 20:02:56 -0800396 ALOGW_IF(mCallback.load().unsafe_get(), "First call to async write with 0 bytes");
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800397 return OK;
398 }
399
400 status_t status;
401 if (!mDataMQ) {
402 // In case if playback starts close to the end of a compressed track, the bytes
403 // that need to be written is less than the actual buffer size. Need to use
404 // full buffer size for the MQ since otherwise after seeking back to the middle
405 // data will be truncated.
406 size_t bufferSize;
407 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
408 return status;
409 }
410 if (bytes > bufferSize) bufferSize = bytes;
411 if ((status = prepareForWriting(bufferSize)) != OK) {
412 return status;
413 }
414 }
415
416 status = callWriterThread(
417 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
418 [&] (const WriteStatus& writeStatus) {
419 *written = writeStatus.reply.written;
420 // Diagnostics of the cause of b/35813113.
421 ALOGE_IF(*written > bytes,
422 "hal reports more bytes written than asked for: %lld > %lld",
423 (long long)*written, (long long)bytes);
424 });
425 mStreamPowerLog.log(buffer, *written);
426 return status;
427}
428
429status_t StreamOutHalHidl::callWriterThread(
430 WriteCommand cmd, const char* cmdName,
431 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
432 if (!mCommandMQ->write(&cmd)) {
433 ALOGE("command message queue write failed for \"%s\"", cmdName);
434 return -EAGAIN;
435 }
436 if (data != nullptr) {
437 size_t availableToWrite = mDataMQ->availableToWrite();
438 if (dataSize > availableToWrite) {
439 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
440 (long long)dataSize, (long long)availableToWrite);
441 dataSize = availableToWrite;
442 }
443 if (!mDataMQ->write(data, dataSize)) {
444 ALOGE("data message queue write failed for \"%s\"", cmdName);
445 }
446 }
447 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
448
449 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
450 uint32_t efState = 0;
451retry:
452 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
453 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
454 WriteStatus writeStatus;
455 writeStatus.retval = Result::NOT_INITIALIZED;
456 if (!mStatusMQ->read(&writeStatus)) {
457 ALOGE("status message read failed for \"%s\"", cmdName);
458 }
459 if (writeStatus.retval == Result::OK) {
460 ret = OK;
461 callback(writeStatus);
462 } else {
463 ret = processReturn(cmdName, writeStatus.retval);
464 }
465 return ret;
466 }
467 if (ret == -EAGAIN || ret == -EINTR) {
468 // Spurious wakeup. This normally retries no more than once.
469 goto retry;
470 }
471 return ret;
472}
473
474status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
475 std::unique_ptr<CommandMQ> tempCommandMQ;
476 std::unique_ptr<DataMQ> tempDataMQ;
477 std::unique_ptr<StatusMQ> tempStatusMQ;
478 Result retval;
479 pid_t halThreadPid, halThreadTid;
480 Return<void> ret = mStream->prepareForWriting(
481 1, bufferSize,
482 [&](Result r,
483 const CommandMQ::Descriptor& commandMQ,
484 const DataMQ::Descriptor& dataMQ,
485 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000486 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800487 retval = r;
488 if (retval == Result::OK) {
489 tempCommandMQ.reset(new CommandMQ(commandMQ));
490 tempDataMQ.reset(new DataMQ(dataMQ));
491 tempStatusMQ.reset(new StatusMQ(statusMQ));
492 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
493 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
494 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000495#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800496 halThreadPid = halThreadInfo.pid;
497 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000498#else
499 halThreadTid = halThreadInfo;
500#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800501 }
502 });
503 if (!ret.isOk() || retval != Result::OK) {
504 return processReturn("prepareForWriting", ret, retval);
505 }
506 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
507 !tempDataMQ || !tempDataMQ->isValid() ||
508 !tempStatusMQ || !tempStatusMQ->isValid() ||
509 !mEfGroup) {
510 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
511 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
512 "Command message queue for writing is invalid");
513 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
514 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
515 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
516 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
517 "Status message queue for writing is invalid");
518 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
519 return NO_INIT;
520 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000521#if MAJOR_VERSION >= 7
522 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
523 return status;
524 }
525#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800526 requestHalThreadPriority(halThreadPid, halThreadTid);
527
528 mCommandMQ = std::move(tempCommandMQ);
529 mDataMQ = std::move(tempDataMQ);
530 mStatusMQ = std::move(tempStatusMQ);
531 mWriterClient = gettid();
532 return OK;
533}
534
535status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
536 if (mStream == 0) return NO_INIT;
537 Result retval;
538 Return<void> ret = mStream->getRenderPosition(
539 [&](Result r, uint32_t d) {
540 retval = r;
541 if (retval == Result::OK) {
542 *dspFrames = d;
543 }
544 });
545 return processReturn("getRenderPosition", ret, retval);
546}
547
548status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
549 if (mStream == 0) return NO_INIT;
550 Result retval;
551 Return<void> ret = mStream->getNextWriteTimestamp(
552 [&](Result r, int64_t t) {
553 retval = r;
554 if (retval == Result::OK) {
555 *timestamp = t;
556 }
557 });
558 return processReturn("getRenderPosition", ret, retval);
559}
560
561status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
562 if (mStream == 0) return NO_INIT;
563 status_t status = processReturn(
564 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
565 if (status == OK) {
566 mCallback = callback;
567 }
568 return status;
569}
570
571status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
572 if (mStream == 0) return NO_INIT;
573 Return<void> ret = mStream->supportsPauseAndResume(
574 [&](bool p, bool r) {
575 *supportsPause = p;
576 *supportsResume = r;
577 });
578 return processReturn("supportsPauseAndResume", ret);
579}
580
581status_t StreamOutHalHidl::pause() {
582 if (mStream == 0) return NO_INIT;
583 return processReturn("pause", mStream->pause());
584}
585
586status_t StreamOutHalHidl::resume() {
587 if (mStream == 0) return NO_INIT;
588 return processReturn("pause", mStream->resume());
589}
590
591status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
592 if (mStream == 0) return NO_INIT;
593 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
594}
595
596status_t StreamOutHalHidl::drain(bool earlyNotify) {
597 if (mStream == 0) return NO_INIT;
598 return processReturn(
599 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
600}
601
602status_t StreamOutHalHidl::flush() {
603 if (mStream == 0) return NO_INIT;
604 return processReturn("pause", mStream->flush());
605}
606
607status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
608 if (mStream == 0) return NO_INIT;
609 if (mWriterClient == gettid() && mCommandMQ) {
610 return callWriterThread(
611 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
612 [&](const WriteStatus& writeStatus) {
613 *frames = writeStatus.reply.presentationPosition.frames;
614 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
615 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
616 });
617 } else {
618 Result retval;
619 Return<void> ret = mStream->getPresentationPosition(
620 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
621 retval = r;
622 if (retval == Result::OK) {
623 *frames = hidlFrames;
624 timestamp->tv_sec = hidlTimeStamp.tvSec;
625 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
626 }
627 });
628 return processReturn("getPresentationPosition", ret, retval);
629 }
630}
631
Kevin Rocard070e7512018-05-22 09:29:13 -0700632#if MAJOR_VERSION == 2
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800633status_t StreamOutHalHidl::updateSourceMetadata(
634 const StreamOutHalInterface::SourceMetadata& /* sourceMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700635 // Audio HAL V2.0 does not support propagating source metadata
636 return INVALID_OPERATION;
637}
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800638#elif MAJOR_VERSION >= 4
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800639status_t StreamOutHalHidl::updateSourceMetadata(
640 const StreamOutHalInterface::SourceMetadata& sourceMetadata) {
Mikhail Naganovea1f19d2022-01-27 22:17:21 +0000641#if MAJOR_VERSION == 4
642 ::android::hardware::audio::CORE_TYPES_CPP_VERSION::SourceMetadata hidlMetadata;
643#else
644 ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::SourceMetadata hidlMetadata;
645#endif
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000646 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
Mikhail Naganovea1f19d2022-01-27 22:17:21 +0000756#include PATH(android/hardware/audio/CORE_TYPES_FILE_VERSION/IStreamOutEventCallback.h)
jiabinf6eb4c32020-02-25 14:06:25 -0800757
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
Mikhail Naganovea1f19d2022-01-27 22:17:21 +0000821StreamInHalHidl::StreamInHalHidl(
822 const sp<::android::hardware::audio::CPP_VERSION::IStreamIn>& stream)
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800823 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
824}
825
826StreamInHalHidl::~StreamInHalHidl() {
827 if (mStream != 0) {
828 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800829 }
830 if (mEfGroup) {
831 EventFlag::deleteEventFlag(&mEfGroup);
832 }
833}
834
835status_t StreamInHalHidl::getFrameSize(size_t *size) {
836 if (mStream == 0) return NO_INIT;
837 return processReturn("getFrameSize", mStream->getFrameSize(), size);
838}
839
840status_t StreamInHalHidl::setGain(float gain) {
841 if (mStream == 0) return NO_INIT;
842 return processReturn("setGain", mStream->setGain(gain));
843}
844
845status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
846 if (mStream == 0) return NO_INIT;
847 *read = 0;
848
849 if (bytes == 0 && !mDataMQ) {
850 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
851 return OK;
852 }
853
854 status_t status;
855 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
856 return status;
857 }
858
859 ReadParameters params;
860 params.command = ReadCommand::READ;
861 params.params.read = bytes;
862 status = callReaderThread(params, "read",
863 [&](const ReadStatus& readStatus) {
864 const size_t availToRead = mDataMQ->availableToRead();
865 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
866 ALOGE("data message queue read failed for \"read\"");
867 }
868 ALOGW_IF(availToRead != readStatus.reply.read,
869 "HAL read report inconsistent: mq = %d, status = %d",
870 (int32_t)availToRead, (int32_t)readStatus.reply.read);
871 *read = readStatus.reply.read;
872 });
873 mStreamPowerLog.log(buffer, *read);
874 return status;
875}
876
877status_t StreamInHalHidl::callReaderThread(
878 const ReadParameters& params, const char* cmdName,
879 StreamInHalHidl::ReaderCallback callback) {
880 if (!mCommandMQ->write(&params)) {
881 ALOGW("command message queue write failed");
882 return -EAGAIN;
883 }
884 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
885
886 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
887 uint32_t efState = 0;
888retry:
889 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
890 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
891 ReadStatus readStatus;
892 readStatus.retval = Result::NOT_INITIALIZED;
893 if (!mStatusMQ->read(&readStatus)) {
894 ALOGE("status message read failed for \"%s\"", cmdName);
895 }
896 if (readStatus.retval == Result::OK) {
897 ret = OK;
898 callback(readStatus);
899 } else {
900 ret = processReturn(cmdName, readStatus.retval);
901 }
902 return ret;
903 }
904 if (ret == -EAGAIN || ret == -EINTR) {
905 // Spurious wakeup. This normally retries no more than once.
906 goto retry;
907 }
908 return ret;
909}
910
911status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
912 std::unique_ptr<CommandMQ> tempCommandMQ;
913 std::unique_ptr<DataMQ> tempDataMQ;
914 std::unique_ptr<StatusMQ> tempStatusMQ;
915 Result retval;
916 pid_t halThreadPid, halThreadTid;
917 Return<void> ret = mStream->prepareForReading(
918 1, bufferSize,
919 [&](Result r,
920 const CommandMQ::Descriptor& commandMQ,
921 const DataMQ::Descriptor& dataMQ,
922 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000923 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800924 retval = r;
925 if (retval == Result::OK) {
926 tempCommandMQ.reset(new CommandMQ(commandMQ));
927 tempDataMQ.reset(new DataMQ(dataMQ));
928 tempStatusMQ.reset(new StatusMQ(statusMQ));
929 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
930 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
931 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000932#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800933 halThreadPid = halThreadInfo.pid;
934 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000935#else
936 halThreadTid = halThreadInfo;
937#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800938 }
939 });
940 if (!ret.isOk() || retval != Result::OK) {
941 return processReturn("prepareForReading", ret, retval);
942 }
943 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
944 !tempDataMQ || !tempDataMQ->isValid() ||
945 !tempStatusMQ || !tempStatusMQ->isValid() ||
946 !mEfGroup) {
947 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
948 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
949 "Command message queue for writing is invalid");
950 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
951 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
952 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
953 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
954 "Status message queue for reading is invalid");
955 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
956 return NO_INIT;
957 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000958#if MAJOR_VERSION >= 7
959 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
960 return status;
961 }
962#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800963 requestHalThreadPriority(halThreadPid, halThreadTid);
964
965 mCommandMQ = std::move(tempCommandMQ);
966 mDataMQ = std::move(tempDataMQ);
967 mStatusMQ = std::move(tempStatusMQ);
968 mReaderClient = gettid();
969 return OK;
970}
971
972status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
973 if (mStream == 0) return NO_INIT;
974 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
975}
976
977status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
978 if (mStream == 0) return NO_INIT;
979 if (mReaderClient == gettid() && mCommandMQ) {
980 ReadParameters params;
981 params.command = ReadCommand::GET_CAPTURE_POSITION;
982 return callReaderThread(params, "getCapturePosition",
983 [&](const ReadStatus& readStatus) {
984 *frames = readStatus.reply.capturePosition.frames;
985 *time = readStatus.reply.capturePosition.time;
986 });
987 } else {
988 Result retval;
989 Return<void> ret = mStream->getCapturePosition(
990 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
991 retval = r;
992 if (retval == Result::OK) {
993 *frames = hidlFrames;
994 *time = hidlTime;
995 }
996 });
997 return processReturn("getCapturePosition", ret, retval);
998 }
999}
1000
Kevin Rocard070e7512018-05-22 09:29:13 -07001001#if MAJOR_VERSION == 2
1002status_t StreamInHalHidl::getActiveMicrophones(
1003 std::vector<media::MicrophoneInfo> *microphones __unused) {
1004 if (mStream == 0) return NO_INIT;
1005 return INVALID_OPERATION;
1006}
1007
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001008status_t StreamInHalHidl::updateSinkMetadata(
1009 const StreamInHalInterface::SinkMetadata& /* sinkMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -07001010 // Audio HAL V2.0 does not support propagating sink metadata
1011 return INVALID_OPERATION;
1012}
1013
Kevin Rocard3d48dce2018-11-08 17:16:57 -08001014#elif MAJOR_VERSION >= 4
jiabin9ff780e2018-03-19 18:19:52 -07001015status_t StreamInHalHidl::getActiveMicrophones(
1016 std::vector<media::MicrophoneInfo> *microphonesInfo) {
1017 if (!mStream) return NO_INIT;
1018 Result retval;
1019 Return<void> ret = mStream->getActiveMicrophones(
1020 [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
1021 retval = r;
1022 for (size_t k = 0; k < micArrayHal.size(); k++) {
1023 audio_microphone_characteristic_t dst;
1024 // convert
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001025 (void)CoreUtils::microphoneInfoToHal(micArrayHal[k], &dst);
jiabin9ff780e2018-03-19 18:19:52 -07001026 media::MicrophoneInfo microphone = media::MicrophoneInfo(dst);
1027 microphonesInfo->push_back(microphone);
1028 }
1029 });
1030 return processReturn("getActiveMicrophones", ret, retval);
1031}
1032
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001033status_t StreamInHalHidl::updateSinkMetadata(const
1034 StreamInHalInterface::SinkMetadata& sinkMetadata) {
Mikhail Naganovea1f19d2022-01-27 22:17:21 +00001035#if MAJOR_VERSION == 4
1036 ::android::hardware::audio::CORE_TYPES_CPP_VERSION::SinkMetadata hidlMetadata;
1037#else
1038 ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::SinkMetadata hidlMetadata;
1039#endif
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001040 if (status_t status = CoreUtils::sinkMetadataFromHalV7(
1041 sinkMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
1042 status != OK) {
1043 return status;
1044 }
1045 return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -07001046}
Kevin Rocard070e7512018-05-22 09:29:13 -07001047#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -07001048
Paul McLean03a6e6a2018-12-04 10:54:13 -07001049#if MAJOR_VERSION < 5
Paul McLean12340082019-03-19 09:35:05 -06001050status_t StreamInHalHidl::setPreferredMicrophoneDirection(
1051 audio_microphone_direction_t direction __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001052 if (mStream == 0) return NO_INIT;
1053 return INVALID_OPERATION;
1054}
1055
Paul McLean12340082019-03-19 09:35:05 -06001056status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001057 if (mStream == 0) return NO_INIT;
1058 return INVALID_OPERATION;
1059}
1060#else
Paul McLean12340082019-03-19 09:35:05 -06001061status_t StreamInHalHidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001062 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001063 return processReturn("setPreferredMicrophoneDirection",
1064 mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction)));
Paul McLean03a6e6a2018-12-04 10:54:13 -07001065}
1066
Paul McLean12340082019-03-19 09:35:05 -06001067status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001068 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001069 return processReturn("setPreferredMicrophoneFieldDimension",
Paul McLean03a6e6a2018-12-04 10:54:13 -07001070 mStream->setMicrophoneFieldDimension(zoom));
1071}
1072#endif
1073
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001074} // namespace android