blob: 452f84d8d7b99c6dc4bf4c4d64f6f8ef5ca40ccb [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
Andy Hung61589a42021-06-16 09:37:53 -0700155status_t StreamHalHidl::dump(int fd, const Vector<String16>& args) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800156 if (!mStream) return NO_INIT;
157 native_handle_t* hidlHandle = native_handle_create(1, 0);
158 hidlHandle->data[0] = fd;
Andy Hung61589a42021-06-16 09:37:53 -0700159 hidl_vec<hidl_string> hidlArgs;
160 argsFromHal(args, &hidlArgs);
161 Return<void> ret = mStream->debug(hidlHandle, hidlArgs);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800162 native_handle_delete(hidlHandle);
163 mStreamPowerLog.dump(fd);
164 return processReturn("dump", ret);
165}
166
167status_t StreamHalHidl::start() {
168 if (!mStream) return NO_INIT;
169 return processReturn("start", mStream->start());
170}
171
172status_t StreamHalHidl::stop() {
173 if (!mStream) return NO_INIT;
174 return processReturn("stop", mStream->stop());
175}
176
177status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
178 struct audio_mmap_buffer_info *info) {
179 Result retval;
180 Return<void> ret = mStream->createMmapBuffer(
181 minSizeFrames,
182 [&](Result r, const MmapBufferInfo& hidlInfo) {
183 retval = r;
184 if (retval == Result::OK) {
185 const native_handle *handle = hidlInfo.sharedMemory.handle();
186 if (handle->numFds > 0) {
187 info->shared_memory_fd = handle->data[0];
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800188#if MAJOR_VERSION >= 4
Kevin Rocard734334f2018-07-12 19:37:41 -0700189 info->flags = audio_mmap_buffer_flag(hidlInfo.flags);
190#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800191 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
Kevin Rocard734334f2018-07-12 19:37:41 -0700192 // Negative buffer size frame was a hack in O and P to
193 // indicate that the buffer is shareable to applications
194 if (info->buffer_size_frames < 0) {
195 info->buffer_size_frames *= -1;
196 info->flags = audio_mmap_buffer_flag(
197 info->flags | AUDIO_MMAP_APPLICATION_SHAREABLE);
198 }
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800199 info->burst_size_frames = hidlInfo.burstSizeFrames;
200 // info->shared_memory_address is not needed in HIDL context
201 info->shared_memory_address = NULL;
202 } else {
203 retval = Result::NOT_INITIALIZED;
204 }
205 }
206 });
207 return processReturn("createMmapBuffer", ret, retval);
208}
209
210status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
211 Result retval;
212 Return<void> ret = mStream->getMmapPosition(
213 [&](Result r, const MmapPosition& hidlPosition) {
214 retval = r;
215 if (retval == Result::OK) {
216 position->time_nanoseconds = hidlPosition.timeNanoseconds;
217 position->position_frames = hidlPosition.positionFrames;
218 }
219 });
220 return processReturn("getMmapPosition", ret, retval);
221}
222
223status_t StreamHalHidl::setHalThreadPriority(int priority) {
224 mHalThreadPriority = priority;
225 return OK;
226}
227
228status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
229 if (mCachedBufferSize != 0) {
230 *size = mCachedBufferSize;
231 return OK;
232 }
233 return getBufferSize(size);
234}
235
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000236status_t StreamHalHidl::getHalPid(pid_t *pid) {
237 using ::android::hidl::base::V1_0::DebugInfo;
238 using ::android::hidl::manager::V1_0::IServiceManager;
239
240 DebugInfo debugInfo;
241 auto ret = mStream->getDebugInfo([&] (const auto &info) {
242 debugInfo = info;
243 });
244 if (!ret.isOk()) {
245 return INVALID_OPERATION;
246 }
247 if (debugInfo.pid != (int)IServiceManager::PidConstant::NO_PID) {
248 *pid = debugInfo.pid;
249 return NO_ERROR;
250 }
251 return NAME_NOT_FOUND;
252}
253
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800254bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
255 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
256 return true;
257 }
258 int err = requestPriority(
259 threadPid, threadId,
260 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
261 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
262 mHalThreadPriority, threadPid, threadId, err);
263 // Audio will still work, but latency will be higher and sometimes unacceptable.
264 return err == 0;
265}
266
267namespace {
268
269/* Notes on callback ownership.
270
271This is how (Hw)Binder ownership model looks like. The server implementation
272is owned by Binder framework (via sp<>). Proxies are owned by clients.
273When the last proxy disappears, Binder framework releases the server impl.
274
275Thus, it is not needed to keep any references to StreamOutCallback (this is
276the server impl) -- it will live as long as HAL server holds a strong ref to
277IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
278from the destructor of StreamOutHalHidl.
279
280The callback only keeps a weak reference to the stream. The stream is owned
281by AudioFlinger.
282
283*/
284
285struct StreamOutCallback : public IStreamOutCallback {
286 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
287
288 // IStreamOutCallback implementation
289 Return<void> onWriteReady() override {
290 sp<StreamOutHalHidl> stream = mStream.promote();
291 if (stream != 0) {
292 stream->onWriteReady();
293 }
294 return Void();
295 }
296
297 Return<void> onDrainReady() override {
298 sp<StreamOutHalHidl> stream = mStream.promote();
299 if (stream != 0) {
300 stream->onDrainReady();
301 }
302 return Void();
303 }
304
305 Return<void> onError() override {
306 sp<StreamOutHalHidl> stream = mStream.promote();
307 if (stream != 0) {
308 stream->onError();
309 }
310 return Void();
311 }
312
313 private:
Andy Hung638f45b2021-01-18 20:02:56 -0800314 const wp<StreamOutHalHidl> mStream;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800315};
316
317} // namespace
318
319StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
320 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
321}
322
323StreamOutHalHidl::~StreamOutHalHidl() {
324 if (mStream != 0) {
Andy Hung638f45b2021-01-18 20:02:56 -0800325 if (mCallback.load().unsafe_get()) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800326 processReturn("clearCallback", mStream->clearCallback());
327 }
jiabinf6eb4c32020-02-25 14:06:25 -0800328#if MAJOR_VERSION >= 6
Andy Hung638f45b2021-01-18 20:02:56 -0800329 if (mEventCallback.load().unsafe_get() != nullptr) {
jiabinf6eb4c32020-02-25 14:06:25 -0800330 processReturn("setEventCallback",
331 mStream->setEventCallback(nullptr));
332 }
333#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800334 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800335 }
Andy Hung638f45b2021-01-18 20:02:56 -0800336 mCallback = nullptr;
337 mEventCallback = nullptr;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800338 if (mEfGroup) {
339 EventFlag::deleteEventFlag(&mEfGroup);
340 }
341}
342
343status_t StreamOutHalHidl::getFrameSize(size_t *size) {
344 if (mStream == 0) return NO_INIT;
345 return processReturn("getFrameSize", mStream->getFrameSize(), size);
346}
347
348status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
349 if (mStream == 0) return NO_INIT;
350 if (mWriterClient == gettid() && mCommandMQ) {
351 return callWriterThread(
352 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
353 [&](const WriteStatus& writeStatus) {
354 *latency = writeStatus.reply.latencyMs;
355 });
356 } else {
357 return processReturn("getLatency", mStream->getLatency(), latency);
358 }
359}
360
361status_t StreamOutHalHidl::setVolume(float left, float right) {
362 if (mStream == 0) return NO_INIT;
363 return processReturn("setVolume", mStream->setVolume(left, right));
364}
365
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800366#if MAJOR_VERSION == 2
367status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
368 if (mStream == 0) return NO_INIT;
369 std::vector<ParameterValue> parameters;
370 String8 halParameters;
371 parameters.push_back({AudioParameter::keyPresentationId, std::to_string(presentationId)});
372 parameters.push_back({AudioParameter::keyProgramId, std::to_string(programId)});
373 parametersToHal(hidl_vec<ParameterValue>(parameters), &halParameters);
374 return setParameters(halParameters);
375}
Kevin Rocard1cf6b4d2018-11-20 18:05:44 -0800376#elif MAJOR_VERSION >= 4
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800377status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
378 if (mStream == 0) return NO_INIT;
379 return processReturn("selectPresentation",
380 mStream->selectPresentation(presentationId, programId));
381}
382#endif
383
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800384status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
385 if (mStream == 0) return NO_INIT;
386 *written = 0;
387
388 if (bytes == 0 && !mDataMQ) {
389 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
Andy Hung638f45b2021-01-18 20:02:56 -0800390 ALOGW_IF(mCallback.load().unsafe_get(), "First call to async write with 0 bytes");
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800391 return OK;
392 }
393
394 status_t status;
395 if (!mDataMQ) {
396 // In case if playback starts close to the end of a compressed track, the bytes
397 // that need to be written is less than the actual buffer size. Need to use
398 // full buffer size for the MQ since otherwise after seeking back to the middle
399 // data will be truncated.
400 size_t bufferSize;
401 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
402 return status;
403 }
404 if (bytes > bufferSize) bufferSize = bytes;
405 if ((status = prepareForWriting(bufferSize)) != OK) {
406 return status;
407 }
408 }
409
410 status = callWriterThread(
411 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
412 [&] (const WriteStatus& writeStatus) {
413 *written = writeStatus.reply.written;
414 // Diagnostics of the cause of b/35813113.
415 ALOGE_IF(*written > bytes,
416 "hal reports more bytes written than asked for: %lld > %lld",
417 (long long)*written, (long long)bytes);
418 });
419 mStreamPowerLog.log(buffer, *written);
420 return status;
421}
422
423status_t StreamOutHalHidl::callWriterThread(
424 WriteCommand cmd, const char* cmdName,
425 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
426 if (!mCommandMQ->write(&cmd)) {
427 ALOGE("command message queue write failed for \"%s\"", cmdName);
428 return -EAGAIN;
429 }
430 if (data != nullptr) {
431 size_t availableToWrite = mDataMQ->availableToWrite();
432 if (dataSize > availableToWrite) {
433 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
434 (long long)dataSize, (long long)availableToWrite);
435 dataSize = availableToWrite;
436 }
437 if (!mDataMQ->write(data, dataSize)) {
438 ALOGE("data message queue write failed for \"%s\"", cmdName);
439 }
440 }
441 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
442
443 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
444 uint32_t efState = 0;
445retry:
446 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
447 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
448 WriteStatus writeStatus;
449 writeStatus.retval = Result::NOT_INITIALIZED;
450 if (!mStatusMQ->read(&writeStatus)) {
451 ALOGE("status message read failed for \"%s\"", cmdName);
452 }
453 if (writeStatus.retval == Result::OK) {
454 ret = OK;
455 callback(writeStatus);
456 } else {
457 ret = processReturn(cmdName, writeStatus.retval);
458 }
459 return ret;
460 }
461 if (ret == -EAGAIN || ret == -EINTR) {
462 // Spurious wakeup. This normally retries no more than once.
463 goto retry;
464 }
465 return ret;
466}
467
468status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
469 std::unique_ptr<CommandMQ> tempCommandMQ;
470 std::unique_ptr<DataMQ> tempDataMQ;
471 std::unique_ptr<StatusMQ> tempStatusMQ;
472 Result retval;
473 pid_t halThreadPid, halThreadTid;
474 Return<void> ret = mStream->prepareForWriting(
475 1, bufferSize,
476 [&](Result r,
477 const CommandMQ::Descriptor& commandMQ,
478 const DataMQ::Descriptor& dataMQ,
479 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000480 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800481 retval = r;
482 if (retval == Result::OK) {
483 tempCommandMQ.reset(new CommandMQ(commandMQ));
484 tempDataMQ.reset(new DataMQ(dataMQ));
485 tempStatusMQ.reset(new StatusMQ(statusMQ));
486 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
487 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
488 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000489#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800490 halThreadPid = halThreadInfo.pid;
491 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000492#else
493 halThreadTid = halThreadInfo;
494#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800495 }
496 });
497 if (!ret.isOk() || retval != Result::OK) {
498 return processReturn("prepareForWriting", ret, retval);
499 }
500 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
501 !tempDataMQ || !tempDataMQ->isValid() ||
502 !tempStatusMQ || !tempStatusMQ->isValid() ||
503 !mEfGroup) {
504 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
505 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
506 "Command message queue for writing is invalid");
507 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
508 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
509 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
510 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
511 "Status message queue for writing is invalid");
512 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
513 return NO_INIT;
514 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000515#if MAJOR_VERSION >= 7
516 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
517 return status;
518 }
519#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800520 requestHalThreadPriority(halThreadPid, halThreadTid);
521
522 mCommandMQ = std::move(tempCommandMQ);
523 mDataMQ = std::move(tempDataMQ);
524 mStatusMQ = std::move(tempStatusMQ);
525 mWriterClient = gettid();
526 return OK;
527}
528
529status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
530 if (mStream == 0) return NO_INIT;
531 Result retval;
532 Return<void> ret = mStream->getRenderPosition(
533 [&](Result r, uint32_t d) {
534 retval = r;
535 if (retval == Result::OK) {
536 *dspFrames = d;
537 }
538 });
539 return processReturn("getRenderPosition", ret, retval);
540}
541
542status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
543 if (mStream == 0) return NO_INIT;
544 Result retval;
545 Return<void> ret = mStream->getNextWriteTimestamp(
546 [&](Result r, int64_t t) {
547 retval = r;
548 if (retval == Result::OK) {
549 *timestamp = t;
550 }
551 });
552 return processReturn("getRenderPosition", ret, retval);
553}
554
555status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
556 if (mStream == 0) return NO_INIT;
557 status_t status = processReturn(
558 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
559 if (status == OK) {
560 mCallback = callback;
561 }
562 return status;
563}
564
565status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
566 if (mStream == 0) return NO_INIT;
567 Return<void> ret = mStream->supportsPauseAndResume(
568 [&](bool p, bool r) {
569 *supportsPause = p;
570 *supportsResume = r;
571 });
572 return processReturn("supportsPauseAndResume", ret);
573}
574
575status_t StreamOutHalHidl::pause() {
576 if (mStream == 0) return NO_INIT;
577 return processReturn("pause", mStream->pause());
578}
579
580status_t StreamOutHalHidl::resume() {
581 if (mStream == 0) return NO_INIT;
582 return processReturn("pause", mStream->resume());
583}
584
585status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
586 if (mStream == 0) return NO_INIT;
587 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
588}
589
590status_t StreamOutHalHidl::drain(bool earlyNotify) {
591 if (mStream == 0) return NO_INIT;
592 return processReturn(
593 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
594}
595
596status_t StreamOutHalHidl::flush() {
597 if (mStream == 0) return NO_INIT;
598 return processReturn("pause", mStream->flush());
599}
600
601status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
602 if (mStream == 0) return NO_INIT;
603 if (mWriterClient == gettid() && mCommandMQ) {
604 return callWriterThread(
605 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
606 [&](const WriteStatus& writeStatus) {
607 *frames = writeStatus.reply.presentationPosition.frames;
608 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
609 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
610 });
611 } else {
612 Result retval;
613 Return<void> ret = mStream->getPresentationPosition(
614 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
615 retval = r;
616 if (retval == Result::OK) {
617 *frames = hidlFrames;
618 timestamp->tv_sec = hidlTimeStamp.tvSec;
619 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
620 }
621 });
622 return processReturn("getPresentationPosition", ret, retval);
623 }
624}
625
Kevin Rocard070e7512018-05-22 09:29:13 -0700626#if MAJOR_VERSION == 2
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800627status_t StreamOutHalHidl::updateSourceMetadata(
628 const StreamOutHalInterface::SourceMetadata& /* sourceMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700629 // Audio HAL V2.0 does not support propagating source metadata
630 return INVALID_OPERATION;
631}
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800632#elif MAJOR_VERSION >= 4
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800633status_t StreamOutHalHidl::updateSourceMetadata(
634 const StreamOutHalInterface::SourceMetadata& sourceMetadata) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000635 CPP_VERSION::SourceMetadata hidlMetadata;
636 if (status_t status = CoreUtils::sourceMetadataFromHalV7(
637 sourceMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
638 status != OK) {
639 return status;
640 }
641 return processReturn("updateSourceMetadata", mStream->updateSourceMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -0700642}
Kevin Rocard070e7512018-05-22 09:29:13 -0700643#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700644
jiabinf6eb4c32020-02-25 14:06:25 -0800645#if MAJOR_VERSION < 6
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800646status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode __unused) {
647 return INVALID_OPERATION;
648}
649
650status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode __unused) {
651 return INVALID_OPERATION;
652}
653
654status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB __unused) {
655 return INVALID_OPERATION;
656}
657
658status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB __unused) {
659 return INVALID_OPERATION;
660}
661
662status_t StreamOutHalHidl::getPlaybackRateParameters(
663 audio_playback_rate_t* playbackRate __unused) {
664 return INVALID_OPERATION;
665}
666
667status_t StreamOutHalHidl::setPlaybackRateParameters(
668 const audio_playback_rate_t& playbackRate __unused) {
669 return INVALID_OPERATION;
670}
671
jiabinf6eb4c32020-02-25 14:06:25 -0800672status_t StreamOutHalHidl::setEventCallback(
673 const sp<StreamOutHalInterfaceEventCallback>& callback __unused) {
674 // Codec format callback is supported starting from audio HAL V6.0
675 return INVALID_OPERATION;
676}
677#else
678
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800679status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode) {
680 if (mStream == 0) return NO_INIT;
681 Result retval;
682 Return<void> ret = mStream->getDualMonoMode(
683 [&](Result r, DualMonoMode hidlMode) {
684 retval = r;
685 if (retval == Result::OK) {
686 *mode = static_cast<audio_dual_mono_mode_t>(hidlMode);
687 }
688 });
689 return processReturn("getDualMonoMode", ret, retval);
690}
691
692status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode) {
693 if (mStream == 0) return NO_INIT;
694 return processReturn(
695 "setDualMonoMode", mStream->setDualMonoMode(static_cast<DualMonoMode>(mode)));
696}
697
698status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB) {
699 if (mStream == 0) return NO_INIT;
700 Result retval;
701 Return<void> ret = mStream->getAudioDescriptionMixLevel(
702 [&](Result r, float hidlLeveldB) {
703 retval = r;
704 if (retval == Result::OK) {
705 *leveldB = hidlLeveldB;
706 }
707 });
708 return processReturn("getAudioDescriptionMixLevel", ret, retval);
709}
710
711status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB) {
712 if (mStream == 0) return NO_INIT;
713 return processReturn(
714 "setAudioDescriptionMixLevel", mStream->setAudioDescriptionMixLevel(leveldB));
715}
716
717status_t StreamOutHalHidl::getPlaybackRateParameters(audio_playback_rate_t* playbackRate) {
718 if (mStream == 0) return NO_INIT;
719 Result retval;
720 Return<void> ret = mStream->getPlaybackRateParameters(
721 [&](Result r, PlaybackRate hidlPlaybackRate) {
722 retval = r;
723 if (retval == Result::OK) {
724 playbackRate->mSpeed = hidlPlaybackRate.speed;
725 playbackRate->mPitch = hidlPlaybackRate.pitch;
726 playbackRate->mStretchMode =
727 static_cast<audio_timestretch_stretch_mode_t>(
728 hidlPlaybackRate.timestretchMode);
729 playbackRate->mFallbackMode =
730 static_cast<audio_timestretch_fallback_mode_t>(
731 hidlPlaybackRate.fallbackMode);
732 }
733 });
734 return processReturn("getPlaybackRateParameters", ret, retval);
735}
736
737status_t StreamOutHalHidl::setPlaybackRateParameters(const audio_playback_rate_t& playbackRate) {
738 if (mStream == 0) return NO_INIT;
739 return processReturn(
740 "setPlaybackRateParameters", mStream->setPlaybackRateParameters(
741 PlaybackRate{playbackRate.mSpeed, playbackRate.mPitch,
742 static_cast<TimestretchMode>(playbackRate.mStretchMode),
743 static_cast<TimestretchFallbackMode>(playbackRate.mFallbackMode)}));
744}
745
jiabinf6eb4c32020-02-25 14:06:25 -0800746#include PATH(android/hardware/audio/FILE_VERSION/IStreamOutEventCallback.h)
747
748namespace {
749
750struct StreamOutEventCallback : public IStreamOutEventCallback {
751 StreamOutEventCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
752
753 // IStreamOutEventCallback implementation
754 Return<void> onCodecFormatChanged(
755 const android::hardware::hidl_vec<uint8_t>& audioMetadata) override {
756 sp<StreamOutHalHidl> stream = mStream.promote();
757 if (stream != nullptr) {
758 std::basic_string<uint8_t> metadataBs(audioMetadata.begin(), audioMetadata.end());
759 stream->onCodecFormatChanged(metadataBs);
760 }
761 return Void();
762 }
763
764 private:
765 wp<StreamOutHalHidl> mStream;
766};
767
768} // namespace
769
770status_t StreamOutHalHidl::setEventCallback(
771 const sp<StreamOutHalInterfaceEventCallback>& callback) {
772 if (mStream == nullptr) return NO_INIT;
773 mEventCallback = callback;
774 status_t status = processReturn(
775 "setEventCallback",
776 mStream->setEventCallback(
777 callback.get() == nullptr ? nullptr : new StreamOutEventCallback(this)));
778 return status;
779}
780#endif
781
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800782void StreamOutHalHidl::onWriteReady() {
Andy Hung638f45b2021-01-18 20:02:56 -0800783 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800784 if (callback == 0) return;
785 ALOGV("asyncCallback onWriteReady");
786 callback->onWriteReady();
787}
788
789void StreamOutHalHidl::onDrainReady() {
Andy Hung638f45b2021-01-18 20:02:56 -0800790 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800791 if (callback == 0) return;
792 ALOGV("asyncCallback onDrainReady");
793 callback->onDrainReady();
794}
795
796void StreamOutHalHidl::onError() {
Andy Hung638f45b2021-01-18 20:02:56 -0800797 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800798 if (callback == 0) return;
799 ALOGV("asyncCallback onError");
800 callback->onError();
801}
802
jiabinf6eb4c32020-02-25 14:06:25 -0800803void StreamOutHalHidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) {
Andy Hung638f45b2021-01-18 20:02:56 -0800804 sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.load().promote();
jiabinf6eb4c32020-02-25 14:06:25 -0800805 if (callback == nullptr) return;
806 ALOGV("asyncCodecFormatCallback %s", __func__);
807 callback->onCodecFormatChanged(metadataBs);
808}
809
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800810
811StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
812 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
813}
814
815StreamInHalHidl::~StreamInHalHidl() {
816 if (mStream != 0) {
817 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800818 }
819 if (mEfGroup) {
820 EventFlag::deleteEventFlag(&mEfGroup);
821 }
822}
823
824status_t StreamInHalHidl::getFrameSize(size_t *size) {
825 if (mStream == 0) return NO_INIT;
826 return processReturn("getFrameSize", mStream->getFrameSize(), size);
827}
828
829status_t StreamInHalHidl::setGain(float gain) {
830 if (mStream == 0) return NO_INIT;
831 return processReturn("setGain", mStream->setGain(gain));
832}
833
834status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
835 if (mStream == 0) return NO_INIT;
836 *read = 0;
837
838 if (bytes == 0 && !mDataMQ) {
839 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
840 return OK;
841 }
842
843 status_t status;
844 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
845 return status;
846 }
847
848 ReadParameters params;
849 params.command = ReadCommand::READ;
850 params.params.read = bytes;
851 status = callReaderThread(params, "read",
852 [&](const ReadStatus& readStatus) {
853 const size_t availToRead = mDataMQ->availableToRead();
854 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
855 ALOGE("data message queue read failed for \"read\"");
856 }
857 ALOGW_IF(availToRead != readStatus.reply.read,
858 "HAL read report inconsistent: mq = %d, status = %d",
859 (int32_t)availToRead, (int32_t)readStatus.reply.read);
860 *read = readStatus.reply.read;
861 });
862 mStreamPowerLog.log(buffer, *read);
863 return status;
864}
865
866status_t StreamInHalHidl::callReaderThread(
867 const ReadParameters& params, const char* cmdName,
868 StreamInHalHidl::ReaderCallback callback) {
869 if (!mCommandMQ->write(&params)) {
870 ALOGW("command message queue write failed");
871 return -EAGAIN;
872 }
873 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
874
875 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
876 uint32_t efState = 0;
877retry:
878 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
879 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
880 ReadStatus readStatus;
881 readStatus.retval = Result::NOT_INITIALIZED;
882 if (!mStatusMQ->read(&readStatus)) {
883 ALOGE("status message read failed for \"%s\"", cmdName);
884 }
885 if (readStatus.retval == Result::OK) {
886 ret = OK;
887 callback(readStatus);
888 } else {
889 ret = processReturn(cmdName, readStatus.retval);
890 }
891 return ret;
892 }
893 if (ret == -EAGAIN || ret == -EINTR) {
894 // Spurious wakeup. This normally retries no more than once.
895 goto retry;
896 }
897 return ret;
898}
899
900status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
901 std::unique_ptr<CommandMQ> tempCommandMQ;
902 std::unique_ptr<DataMQ> tempDataMQ;
903 std::unique_ptr<StatusMQ> tempStatusMQ;
904 Result retval;
905 pid_t halThreadPid, halThreadTid;
906 Return<void> ret = mStream->prepareForReading(
907 1, bufferSize,
908 [&](Result r,
909 const CommandMQ::Descriptor& commandMQ,
910 const DataMQ::Descriptor& dataMQ,
911 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000912 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800913 retval = r;
914 if (retval == Result::OK) {
915 tempCommandMQ.reset(new CommandMQ(commandMQ));
916 tempDataMQ.reset(new DataMQ(dataMQ));
917 tempStatusMQ.reset(new StatusMQ(statusMQ));
918 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
919 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
920 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000921#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800922 halThreadPid = halThreadInfo.pid;
923 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000924#else
925 halThreadTid = halThreadInfo;
926#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800927 }
928 });
929 if (!ret.isOk() || retval != Result::OK) {
930 return processReturn("prepareForReading", ret, retval);
931 }
932 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
933 !tempDataMQ || !tempDataMQ->isValid() ||
934 !tempStatusMQ || !tempStatusMQ->isValid() ||
935 !mEfGroup) {
936 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
937 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
938 "Command message queue for writing is invalid");
939 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
940 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
941 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
942 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
943 "Status message queue for reading is invalid");
944 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
945 return NO_INIT;
946 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000947#if MAJOR_VERSION >= 7
948 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
949 return status;
950 }
951#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800952 requestHalThreadPriority(halThreadPid, halThreadTid);
953
954 mCommandMQ = std::move(tempCommandMQ);
955 mDataMQ = std::move(tempDataMQ);
956 mStatusMQ = std::move(tempStatusMQ);
957 mReaderClient = gettid();
958 return OK;
959}
960
961status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
962 if (mStream == 0) return NO_INIT;
963 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
964}
965
966status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
967 if (mStream == 0) return NO_INIT;
968 if (mReaderClient == gettid() && mCommandMQ) {
969 ReadParameters params;
970 params.command = ReadCommand::GET_CAPTURE_POSITION;
971 return callReaderThread(params, "getCapturePosition",
972 [&](const ReadStatus& readStatus) {
973 *frames = readStatus.reply.capturePosition.frames;
974 *time = readStatus.reply.capturePosition.time;
975 });
976 } else {
977 Result retval;
978 Return<void> ret = mStream->getCapturePosition(
979 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
980 retval = r;
981 if (retval == Result::OK) {
982 *frames = hidlFrames;
983 *time = hidlTime;
984 }
985 });
986 return processReturn("getCapturePosition", ret, retval);
987 }
988}
989
Kevin Rocard070e7512018-05-22 09:29:13 -0700990#if MAJOR_VERSION == 2
991status_t StreamInHalHidl::getActiveMicrophones(
992 std::vector<media::MicrophoneInfo> *microphones __unused) {
993 if (mStream == 0) return NO_INIT;
994 return INVALID_OPERATION;
995}
996
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800997status_t StreamInHalHidl::updateSinkMetadata(
998 const StreamInHalInterface::SinkMetadata& /* sinkMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700999 // Audio HAL V2.0 does not support propagating sink metadata
1000 return INVALID_OPERATION;
1001}
1002
Kevin Rocard3d48dce2018-11-08 17:16:57 -08001003#elif MAJOR_VERSION >= 4
jiabin9ff780e2018-03-19 18:19:52 -07001004status_t StreamInHalHidl::getActiveMicrophones(
1005 std::vector<media::MicrophoneInfo> *microphonesInfo) {
1006 if (!mStream) return NO_INIT;
1007 Result retval;
1008 Return<void> ret = mStream->getActiveMicrophones(
1009 [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
1010 retval = r;
1011 for (size_t k = 0; k < micArrayHal.size(); k++) {
1012 audio_microphone_characteristic_t dst;
1013 // convert
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001014 (void)CoreUtils::microphoneInfoToHal(micArrayHal[k], &dst);
jiabin9ff780e2018-03-19 18:19:52 -07001015 media::MicrophoneInfo microphone = media::MicrophoneInfo(dst);
1016 microphonesInfo->push_back(microphone);
1017 }
1018 });
1019 return processReturn("getActiveMicrophones", ret, retval);
1020}
1021
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001022status_t StreamInHalHidl::updateSinkMetadata(const
1023 StreamInHalInterface::SinkMetadata& sinkMetadata) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001024 CPP_VERSION::SinkMetadata hidlMetadata;
1025 if (status_t status = CoreUtils::sinkMetadataFromHalV7(
1026 sinkMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
1027 status != OK) {
1028 return status;
1029 }
1030 return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -07001031}
Kevin Rocard070e7512018-05-22 09:29:13 -07001032#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -07001033
Paul McLean03a6e6a2018-12-04 10:54:13 -07001034#if MAJOR_VERSION < 5
Paul McLean12340082019-03-19 09:35:05 -06001035status_t StreamInHalHidl::setPreferredMicrophoneDirection(
1036 audio_microphone_direction_t direction __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001037 if (mStream == 0) return NO_INIT;
1038 return INVALID_OPERATION;
1039}
1040
Paul McLean12340082019-03-19 09:35:05 -06001041status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001042 if (mStream == 0) return NO_INIT;
1043 return INVALID_OPERATION;
1044}
1045#else
Paul McLean12340082019-03-19 09:35:05 -06001046status_t StreamInHalHidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001047 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001048 return processReturn("setPreferredMicrophoneDirection",
1049 mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction)));
Paul McLean03a6e6a2018-12-04 10:54:13 -07001050}
1051
Paul McLean12340082019-03-19 09:35:05 -06001052status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001053 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001054 return processReturn("setPreferredMicrophoneFieldDimension",
Paul McLean03a6e6a2018-12-04 10:54:13 -07001055 mStream->setMicrophoneFieldDimension(zoom));
1056}
1057#endif
1058
Kevin Rocard070e7512018-05-22 09:29:13 -07001059} // namespace CPP_VERSION
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001060} // namespace android