blob: 097bd121133f23716dab7f7c0391117b3ad53050 [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
Kevin Rocard95213bf2018-11-08 17:16:57 -080020#include PATH(android/hardware/audio/FILE_VERSION/IStreamOutCallback.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
26#include "DeviceHalHidl.h"
27#include "EffectHalHidl.h"
Eric Laurent94579172020-11-20 18:41:04 +010028#include "HidlUtils.h"
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080029#include "StreamHalHidl.h"
Kevin Rocardb9cfbf12018-02-23 19:11:06 -080030#include "VersionUtils.h"
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080031
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080032using ::android::hardware::MQDescriptorSync;
33using ::android::hardware::Return;
34using ::android::hardware::Void;
Kevin Rocarddf9b4202018-05-10 19:56:08 -070035
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080036namespace android {
Kevin Rocard070e7512018-05-22 09:29:13 -070037namespace CPP_VERSION {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080038
Mikhail Naganov595caa32018-12-13 11:08:28 -080039using EffectHalHidl = ::android::effect::CPP_VERSION::EffectHalHidl;
Mikhail Naganov9ccaa162018-12-12 10:27:29 -080040using ReadCommand = ::android::hardware::audio::CPP_VERSION::IStreamIn::ReadCommand;
41
42using namespace ::android::hardware::audio::common::CPP_VERSION;
43using namespace ::android::hardware::audio::CPP_VERSION;
44
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080045StreamHalHidl::StreamHalHidl(IStream *stream)
46 : ConversionHelperHidl("Stream"),
47 mStream(stream),
48 mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT),
49 mCachedBufferSize(0){
50
51 // Instrument audio signal power logging.
52 // Note: This assumes channel mask, format, and sample rate do not change after creation.
Andy Hung8c2e5822019-04-01 18:09:07 -070053 if (mStream != nullptr /* && mStreamPowerLog.isUserDebugOrEngBuild() */) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080054 // Obtain audio properties (see StreamHalHidl::getAudioProperties() below).
55 Return<void> ret = mStream->getAudioProperties(
Kevin Rocardb9cfbf12018-02-23 19:11:06 -080056 [&](auto sr, auto m, auto f) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080057 mStreamPowerLog.init(sr,
58 static_cast<audio_channel_mask_t>(m),
59 static_cast<audio_format_t>(f));
60 });
61 }
62}
63
Andy Hungacb5b982021-01-20 10:12:00 -080064StreamHalHidl::~StreamHalHidl() {
65 // The last step is to flush all binder commands so that the deletion
66 // of IStreamIn / IStreamOut (mStream) is issued with less delay. See b/35394629.
67 hardware::IPCThreadState::self()->flushCommands();
68}
69
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080070status_t StreamHalHidl::getSampleRate(uint32_t *rate) {
71 if (!mStream) return NO_INIT;
72 return processReturn("getSampleRate", mStream->getSampleRate(), rate);
73}
74
75status_t StreamHalHidl::getBufferSize(size_t *size) {
76 if (!mStream) return NO_INIT;
77 status_t status = processReturn("getBufferSize", mStream->getBufferSize(), size);
78 if (status == OK) {
79 mCachedBufferSize = *size;
80 }
81 return status;
82}
83
84status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) {
85 if (!mStream) return NO_INIT;
86 return processReturn("getChannelMask", mStream->getChannelMask(), mask);
87}
88
89status_t StreamHalHidl::getFormat(audio_format_t *format) {
90 if (!mStream) return NO_INIT;
91 return processReturn("getFormat", mStream->getFormat(), format);
92}
93
94status_t StreamHalHidl::getAudioProperties(
95 uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) {
96 if (!mStream) return NO_INIT;
97 Return<void> ret = mStream->getAudioProperties(
Kevin Rocardb9cfbf12018-02-23 19:11:06 -080098 [&](uint32_t sr, auto m, auto f) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080099 *sampleRate = sr;
100 *mask = static_cast<audio_channel_mask_t>(m);
101 *format = static_cast<audio_format_t>(f);
102 });
103 return processReturn("getAudioProperties", ret);
104}
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;
137 return processReturn("addEffect", mStream->addEffect(
138 static_cast<EffectHalHidl*>(effect.get())->effectId()));
139}
140
141status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
142 if (!mStream) return NO_INIT;
143 return processReturn("removeEffect", mStream->removeEffect(
144 static_cast<EffectHalHidl*>(effect.get())->effectId()));
145}
146
147status_t StreamHalHidl::standby() {
148 if (!mStream) return NO_INIT;
149 return processReturn("standby", mStream->standby());
150}
151
152status_t StreamHalHidl::dump(int fd) {
153 if (!mStream) return NO_INIT;
154 native_handle_t* hidlHandle = native_handle_create(1, 0);
155 hidlHandle->data[0] = fd;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800156 Return<void> ret = mStream->debug(hidlHandle, {} /* options */);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800157 native_handle_delete(hidlHandle);
158 mStreamPowerLog.dump(fd);
159 return processReturn("dump", ret);
160}
161
162status_t StreamHalHidl::start() {
163 if (!mStream) return NO_INIT;
164 return processReturn("start", mStream->start());
165}
166
167status_t StreamHalHidl::stop() {
168 if (!mStream) return NO_INIT;
169 return processReturn("stop", mStream->stop());
170}
171
172status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
173 struct audio_mmap_buffer_info *info) {
174 Result retval;
175 Return<void> ret = mStream->createMmapBuffer(
176 minSizeFrames,
177 [&](Result r, const MmapBufferInfo& hidlInfo) {
178 retval = r;
179 if (retval == Result::OK) {
180 const native_handle *handle = hidlInfo.sharedMemory.handle();
181 if (handle->numFds > 0) {
182 info->shared_memory_fd = handle->data[0];
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800183#if MAJOR_VERSION >= 4
Kevin Rocard734334f2018-07-12 19:37:41 -0700184 info->flags = audio_mmap_buffer_flag(hidlInfo.flags);
185#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800186 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
Kevin Rocard734334f2018-07-12 19:37:41 -0700187 // Negative buffer size frame was a hack in O and P to
188 // indicate that the buffer is shareable to applications
189 if (info->buffer_size_frames < 0) {
190 info->buffer_size_frames *= -1;
191 info->flags = audio_mmap_buffer_flag(
192 info->flags | AUDIO_MMAP_APPLICATION_SHAREABLE);
193 }
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800194 info->burst_size_frames = hidlInfo.burstSizeFrames;
195 // info->shared_memory_address is not needed in HIDL context
196 info->shared_memory_address = NULL;
197 } else {
198 retval = Result::NOT_INITIALIZED;
199 }
200 }
201 });
202 return processReturn("createMmapBuffer", ret, retval);
203}
204
205status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
206 Result retval;
207 Return<void> ret = mStream->getMmapPosition(
208 [&](Result r, const MmapPosition& hidlPosition) {
209 retval = r;
210 if (retval == Result::OK) {
211 position->time_nanoseconds = hidlPosition.timeNanoseconds;
212 position->position_frames = hidlPosition.positionFrames;
213 }
214 });
215 return processReturn("getMmapPosition", ret, retval);
216}
217
218status_t StreamHalHidl::setHalThreadPriority(int priority) {
219 mHalThreadPriority = priority;
220 return OK;
221}
222
223status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
224 if (mCachedBufferSize != 0) {
225 *size = mCachedBufferSize;
226 return OK;
227 }
228 return getBufferSize(size);
229}
230
231bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
232 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
233 return true;
234 }
235 int err = requestPriority(
236 threadPid, threadId,
237 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
238 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
239 mHalThreadPriority, threadPid, threadId, err);
240 // Audio will still work, but latency will be higher and sometimes unacceptable.
241 return err == 0;
242}
243
244namespace {
245
246/* Notes on callback ownership.
247
248This is how (Hw)Binder ownership model looks like. The server implementation
249is owned by Binder framework (via sp<>). Proxies are owned by clients.
250When the last proxy disappears, Binder framework releases the server impl.
251
252Thus, it is not needed to keep any references to StreamOutCallback (this is
253the server impl) -- it will live as long as HAL server holds a strong ref to
254IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
255from the destructor of StreamOutHalHidl.
256
257The callback only keeps a weak reference to the stream. The stream is owned
258by AudioFlinger.
259
260*/
261
262struct StreamOutCallback : public IStreamOutCallback {
263 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
264
265 // IStreamOutCallback implementation
266 Return<void> onWriteReady() override {
267 sp<StreamOutHalHidl> stream = mStream.promote();
268 if (stream != 0) {
269 stream->onWriteReady();
270 }
271 return Void();
272 }
273
274 Return<void> onDrainReady() override {
275 sp<StreamOutHalHidl> stream = mStream.promote();
276 if (stream != 0) {
277 stream->onDrainReady();
278 }
279 return Void();
280 }
281
282 Return<void> onError() override {
283 sp<StreamOutHalHidl> stream = mStream.promote();
284 if (stream != 0) {
285 stream->onError();
286 }
287 return Void();
288 }
289
290 private:
Andy Hung638f45b2021-01-18 20:02:56 -0800291 const wp<StreamOutHalHidl> mStream;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800292};
293
294} // namespace
295
296StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
297 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
298}
299
300StreamOutHalHidl::~StreamOutHalHidl() {
301 if (mStream != 0) {
Andy Hung638f45b2021-01-18 20:02:56 -0800302 if (mCallback.load().unsafe_get()) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800303 processReturn("clearCallback", mStream->clearCallback());
304 }
jiabinf6eb4c32020-02-25 14:06:25 -0800305#if MAJOR_VERSION >= 6
Andy Hung638f45b2021-01-18 20:02:56 -0800306 if (mEventCallback.load().unsafe_get() != nullptr) {
jiabinf6eb4c32020-02-25 14:06:25 -0800307 processReturn("setEventCallback",
308 mStream->setEventCallback(nullptr));
309 }
310#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800311 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800312 }
Andy Hung638f45b2021-01-18 20:02:56 -0800313 mCallback = nullptr;
314 mEventCallback = nullptr;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800315 if (mEfGroup) {
316 EventFlag::deleteEventFlag(&mEfGroup);
317 }
318}
319
320status_t StreamOutHalHidl::getFrameSize(size_t *size) {
321 if (mStream == 0) return NO_INIT;
322 return processReturn("getFrameSize", mStream->getFrameSize(), size);
323}
324
325status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
326 if (mStream == 0) return NO_INIT;
327 if (mWriterClient == gettid() && mCommandMQ) {
328 return callWriterThread(
329 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
330 [&](const WriteStatus& writeStatus) {
331 *latency = writeStatus.reply.latencyMs;
332 });
333 } else {
334 return processReturn("getLatency", mStream->getLatency(), latency);
335 }
336}
337
338status_t StreamOutHalHidl::setVolume(float left, float right) {
339 if (mStream == 0) return NO_INIT;
340 return processReturn("setVolume", mStream->setVolume(left, right));
341}
342
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800343#if MAJOR_VERSION == 2
344status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
345 if (mStream == 0) return NO_INIT;
346 std::vector<ParameterValue> parameters;
347 String8 halParameters;
348 parameters.push_back({AudioParameter::keyPresentationId, std::to_string(presentationId)});
349 parameters.push_back({AudioParameter::keyProgramId, std::to_string(programId)});
350 parametersToHal(hidl_vec<ParameterValue>(parameters), &halParameters);
351 return setParameters(halParameters);
352}
Kevin Rocard1cf6b4d2018-11-20 18:05:44 -0800353#elif MAJOR_VERSION >= 4
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800354status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
355 if (mStream == 0) return NO_INIT;
356 return processReturn("selectPresentation",
357 mStream->selectPresentation(presentationId, programId));
358}
359#endif
360
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800361status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
362 if (mStream == 0) return NO_INIT;
363 *written = 0;
364
365 if (bytes == 0 && !mDataMQ) {
366 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
Andy Hung638f45b2021-01-18 20:02:56 -0800367 ALOGW_IF(mCallback.load().unsafe_get(), "First call to async write with 0 bytes");
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800368 return OK;
369 }
370
371 status_t status;
372 if (!mDataMQ) {
373 // In case if playback starts close to the end of a compressed track, the bytes
374 // that need to be written is less than the actual buffer size. Need to use
375 // full buffer size for the MQ since otherwise after seeking back to the middle
376 // data will be truncated.
377 size_t bufferSize;
378 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
379 return status;
380 }
381 if (bytes > bufferSize) bufferSize = bytes;
382 if ((status = prepareForWriting(bufferSize)) != OK) {
383 return status;
384 }
385 }
386
387 status = callWriterThread(
388 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
389 [&] (const WriteStatus& writeStatus) {
390 *written = writeStatus.reply.written;
391 // Diagnostics of the cause of b/35813113.
392 ALOGE_IF(*written > bytes,
393 "hal reports more bytes written than asked for: %lld > %lld",
394 (long long)*written, (long long)bytes);
395 });
396 mStreamPowerLog.log(buffer, *written);
397 return status;
398}
399
400status_t StreamOutHalHidl::callWriterThread(
401 WriteCommand cmd, const char* cmdName,
402 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
403 if (!mCommandMQ->write(&cmd)) {
404 ALOGE("command message queue write failed for \"%s\"", cmdName);
405 return -EAGAIN;
406 }
407 if (data != nullptr) {
408 size_t availableToWrite = mDataMQ->availableToWrite();
409 if (dataSize > availableToWrite) {
410 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
411 (long long)dataSize, (long long)availableToWrite);
412 dataSize = availableToWrite;
413 }
414 if (!mDataMQ->write(data, dataSize)) {
415 ALOGE("data message queue write failed for \"%s\"", cmdName);
416 }
417 }
418 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
419
420 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
421 uint32_t efState = 0;
422retry:
423 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
424 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
425 WriteStatus writeStatus;
426 writeStatus.retval = Result::NOT_INITIALIZED;
427 if (!mStatusMQ->read(&writeStatus)) {
428 ALOGE("status message read failed for \"%s\"", cmdName);
429 }
430 if (writeStatus.retval == Result::OK) {
431 ret = OK;
432 callback(writeStatus);
433 } else {
434 ret = processReturn(cmdName, writeStatus.retval);
435 }
436 return ret;
437 }
438 if (ret == -EAGAIN || ret == -EINTR) {
439 // Spurious wakeup. This normally retries no more than once.
440 goto retry;
441 }
442 return ret;
443}
444
445status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
446 std::unique_ptr<CommandMQ> tempCommandMQ;
447 std::unique_ptr<DataMQ> tempDataMQ;
448 std::unique_ptr<StatusMQ> tempStatusMQ;
449 Result retval;
450 pid_t halThreadPid, halThreadTid;
451 Return<void> ret = mStream->prepareForWriting(
452 1, bufferSize,
453 [&](Result r,
454 const CommandMQ::Descriptor& commandMQ,
455 const DataMQ::Descriptor& dataMQ,
456 const StatusMQ::Descriptor& statusMQ,
457 const ThreadInfo& halThreadInfo) {
458 retval = r;
459 if (retval == Result::OK) {
460 tempCommandMQ.reset(new CommandMQ(commandMQ));
461 tempDataMQ.reset(new DataMQ(dataMQ));
462 tempStatusMQ.reset(new StatusMQ(statusMQ));
463 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
464 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
465 }
466 halThreadPid = halThreadInfo.pid;
467 halThreadTid = halThreadInfo.tid;
468 }
469 });
470 if (!ret.isOk() || retval != Result::OK) {
471 return processReturn("prepareForWriting", ret, retval);
472 }
473 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
474 !tempDataMQ || !tempDataMQ->isValid() ||
475 !tempStatusMQ || !tempStatusMQ->isValid() ||
476 !mEfGroup) {
477 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
478 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
479 "Command message queue for writing is invalid");
480 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
481 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
482 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
483 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
484 "Status message queue for writing is invalid");
485 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
486 return NO_INIT;
487 }
488 requestHalThreadPriority(halThreadPid, halThreadTid);
489
490 mCommandMQ = std::move(tempCommandMQ);
491 mDataMQ = std::move(tempDataMQ);
492 mStatusMQ = std::move(tempStatusMQ);
493 mWriterClient = gettid();
494 return OK;
495}
496
497status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
498 if (mStream == 0) return NO_INIT;
499 Result retval;
500 Return<void> ret = mStream->getRenderPosition(
501 [&](Result r, uint32_t d) {
502 retval = r;
503 if (retval == Result::OK) {
504 *dspFrames = d;
505 }
506 });
507 return processReturn("getRenderPosition", ret, retval);
508}
509
510status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
511 if (mStream == 0) return NO_INIT;
512 Result retval;
513 Return<void> ret = mStream->getNextWriteTimestamp(
514 [&](Result r, int64_t t) {
515 retval = r;
516 if (retval == Result::OK) {
517 *timestamp = t;
518 }
519 });
520 return processReturn("getRenderPosition", ret, retval);
521}
522
523status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
524 if (mStream == 0) return NO_INIT;
525 status_t status = processReturn(
526 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
527 if (status == OK) {
528 mCallback = callback;
529 }
530 return status;
531}
532
533status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
534 if (mStream == 0) return NO_INIT;
535 Return<void> ret = mStream->supportsPauseAndResume(
536 [&](bool p, bool r) {
537 *supportsPause = p;
538 *supportsResume = r;
539 });
540 return processReturn("supportsPauseAndResume", ret);
541}
542
543status_t StreamOutHalHidl::pause() {
544 if (mStream == 0) return NO_INIT;
545 return processReturn("pause", mStream->pause());
546}
547
548status_t StreamOutHalHidl::resume() {
549 if (mStream == 0) return NO_INIT;
550 return processReturn("pause", mStream->resume());
551}
552
553status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
554 if (mStream == 0) return NO_INIT;
555 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
556}
557
558status_t StreamOutHalHidl::drain(bool earlyNotify) {
559 if (mStream == 0) return NO_INIT;
560 return processReturn(
561 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
562}
563
564status_t StreamOutHalHidl::flush() {
565 if (mStream == 0) return NO_INIT;
566 return processReturn("pause", mStream->flush());
567}
568
569status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
570 if (mStream == 0) return NO_INIT;
571 if (mWriterClient == gettid() && mCommandMQ) {
572 return callWriterThread(
573 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
574 [&](const WriteStatus& writeStatus) {
575 *frames = writeStatus.reply.presentationPosition.frames;
576 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
577 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
578 });
579 } else {
580 Result retval;
581 Return<void> ret = mStream->getPresentationPosition(
582 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
583 retval = r;
584 if (retval == Result::OK) {
585 *frames = hidlFrames;
586 timestamp->tv_sec = hidlTimeStamp.tvSec;
587 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
588 }
589 });
590 return processReturn("getPresentationPosition", ret, retval);
591 }
592}
593
Kevin Rocard070e7512018-05-22 09:29:13 -0700594#if MAJOR_VERSION == 2
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800595status_t StreamOutHalHidl::updateSourceMetadata(
596 const StreamOutHalInterface::SourceMetadata& /* sourceMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700597 // Audio HAL V2.0 does not support propagating source metadata
598 return INVALID_OPERATION;
599}
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800600#elif MAJOR_VERSION >= 4
Kevin Rocarda8975a72018-03-27 10:16:52 -0700601/** Transform a standard collection to an HIDL vector. */
602template <class Values, class ElementConverter>
603static auto transformToHidlVec(const Values& values, ElementConverter converter) {
604 hidl_vec<decltype(converter(*values.begin()))> result{values.size()};
605 using namespace std;
606 transform(begin(values), end(values), begin(result), converter);
607 return result;
608}
609
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800610status_t StreamOutHalHidl::updateSourceMetadata(
611 const StreamOutHalInterface::SourceMetadata& sourceMetadata) {
612 CPP_VERSION::SourceMetadata halMetadata = {
Kevin Rocarda8975a72018-03-27 10:16:52 -0700613 .tracks = transformToHidlVec(sourceMetadata.tracks,
Eric Laurent94579172020-11-20 18:41:04 +0100614 [](const playback_track_metadata_v7& metadata) -> PlaybackTrackMetadata {
615 PlaybackTrackMetadata halTrackMetadata = {
616 .usage=static_cast<AudioUsage>(metadata.base.usage),
617 .contentType=static_cast<AudioContentType>(metadata.base.content_type),
618 .gain=metadata.base.gain,
Kevin Rocarda8975a72018-03-27 10:16:52 -0700619 };
Eric Laurent94579172020-11-20 18:41:04 +0100620#if MAJOR_VERSION >= 7
621 HidlUtils::audioChannelMaskFromHal(metadata.channel_mask, false /*isInput*/,
622 &halTrackMetadata.channelMask);
623
624 std::istringstream tags{metadata.tags};
625 std::string tag;
626 while (std::getline(tags, tag, HidlUtils::sAudioTagSeparator)) {
627 if (!tag.empty()) {
628 halTrackMetadata.tags.push_back(tag);
629 }
630 }
631#endif
632 return halTrackMetadata;
Kevin Rocarda8975a72018-03-27 10:16:52 -0700633 })};
634 return processReturn("updateSourceMetadata", mStream->updateSourceMetadata(halMetadata));
635}
Kevin Rocard070e7512018-05-22 09:29:13 -0700636#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700637
jiabinf6eb4c32020-02-25 14:06:25 -0800638#if MAJOR_VERSION < 6
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800639status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode __unused) {
640 return INVALID_OPERATION;
641}
642
643status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode __unused) {
644 return INVALID_OPERATION;
645}
646
647status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB __unused) {
648 return INVALID_OPERATION;
649}
650
651status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB __unused) {
652 return INVALID_OPERATION;
653}
654
655status_t StreamOutHalHidl::getPlaybackRateParameters(
656 audio_playback_rate_t* playbackRate __unused) {
657 return INVALID_OPERATION;
658}
659
660status_t StreamOutHalHidl::setPlaybackRateParameters(
661 const audio_playback_rate_t& playbackRate __unused) {
662 return INVALID_OPERATION;
663}
664
jiabinf6eb4c32020-02-25 14:06:25 -0800665status_t StreamOutHalHidl::setEventCallback(
666 const sp<StreamOutHalInterfaceEventCallback>& callback __unused) {
667 // Codec format callback is supported starting from audio HAL V6.0
668 return INVALID_OPERATION;
669}
670#else
671
Kuowei Lid4adbdb2020-08-13 14:44:25 +0800672status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode) {
673 if (mStream == 0) return NO_INIT;
674 Result retval;
675 Return<void> ret = mStream->getDualMonoMode(
676 [&](Result r, DualMonoMode hidlMode) {
677 retval = r;
678 if (retval == Result::OK) {
679 *mode = static_cast<audio_dual_mono_mode_t>(hidlMode);
680 }
681 });
682 return processReturn("getDualMonoMode", ret, retval);
683}
684
685status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode) {
686 if (mStream == 0) return NO_INIT;
687 return processReturn(
688 "setDualMonoMode", mStream->setDualMonoMode(static_cast<DualMonoMode>(mode)));
689}
690
691status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB) {
692 if (mStream == 0) return NO_INIT;
693 Result retval;
694 Return<void> ret = mStream->getAudioDescriptionMixLevel(
695 [&](Result r, float hidlLeveldB) {
696 retval = r;
697 if (retval == Result::OK) {
698 *leveldB = hidlLeveldB;
699 }
700 });
701 return processReturn("getAudioDescriptionMixLevel", ret, retval);
702}
703
704status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB) {
705 if (mStream == 0) return NO_INIT;
706 return processReturn(
707 "setAudioDescriptionMixLevel", mStream->setAudioDescriptionMixLevel(leveldB));
708}
709
710status_t StreamOutHalHidl::getPlaybackRateParameters(audio_playback_rate_t* playbackRate) {
711 if (mStream == 0) return NO_INIT;
712 Result retval;
713 Return<void> ret = mStream->getPlaybackRateParameters(
714 [&](Result r, PlaybackRate hidlPlaybackRate) {
715 retval = r;
716 if (retval == Result::OK) {
717 playbackRate->mSpeed = hidlPlaybackRate.speed;
718 playbackRate->mPitch = hidlPlaybackRate.pitch;
719 playbackRate->mStretchMode =
720 static_cast<audio_timestretch_stretch_mode_t>(
721 hidlPlaybackRate.timestretchMode);
722 playbackRate->mFallbackMode =
723 static_cast<audio_timestretch_fallback_mode_t>(
724 hidlPlaybackRate.fallbackMode);
725 }
726 });
727 return processReturn("getPlaybackRateParameters", ret, retval);
728}
729
730status_t StreamOutHalHidl::setPlaybackRateParameters(const audio_playback_rate_t& playbackRate) {
731 if (mStream == 0) return NO_INIT;
732 return processReturn(
733 "setPlaybackRateParameters", mStream->setPlaybackRateParameters(
734 PlaybackRate{playbackRate.mSpeed, playbackRate.mPitch,
735 static_cast<TimestretchMode>(playbackRate.mStretchMode),
736 static_cast<TimestretchFallbackMode>(playbackRate.mFallbackMode)}));
737}
738
jiabinf6eb4c32020-02-25 14:06:25 -0800739#include PATH(android/hardware/audio/FILE_VERSION/IStreamOutEventCallback.h)
740
741namespace {
742
743struct StreamOutEventCallback : public IStreamOutEventCallback {
744 StreamOutEventCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
745
746 // IStreamOutEventCallback implementation
747 Return<void> onCodecFormatChanged(
748 const android::hardware::hidl_vec<uint8_t>& audioMetadata) override {
749 sp<StreamOutHalHidl> stream = mStream.promote();
750 if (stream != nullptr) {
751 std::basic_string<uint8_t> metadataBs(audioMetadata.begin(), audioMetadata.end());
752 stream->onCodecFormatChanged(metadataBs);
753 }
754 return Void();
755 }
756
757 private:
758 wp<StreamOutHalHidl> mStream;
759};
760
761} // namespace
762
763status_t StreamOutHalHidl::setEventCallback(
764 const sp<StreamOutHalInterfaceEventCallback>& callback) {
765 if (mStream == nullptr) return NO_INIT;
766 mEventCallback = callback;
767 status_t status = processReturn(
768 "setEventCallback",
769 mStream->setEventCallback(
770 callback.get() == nullptr ? nullptr : new StreamOutEventCallback(this)));
771 return status;
772}
773#endif
774
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800775void StreamOutHalHidl::onWriteReady() {
Andy Hung638f45b2021-01-18 20:02:56 -0800776 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800777 if (callback == 0) return;
778 ALOGV("asyncCallback onWriteReady");
779 callback->onWriteReady();
780}
781
782void StreamOutHalHidl::onDrainReady() {
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 onDrainReady");
786 callback->onDrainReady();
787}
788
789void StreamOutHalHidl::onError() {
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 onError");
793 callback->onError();
794}
795
jiabinf6eb4c32020-02-25 14:06:25 -0800796void StreamOutHalHidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) {
Andy Hung638f45b2021-01-18 20:02:56 -0800797 sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.load().promote();
jiabinf6eb4c32020-02-25 14:06:25 -0800798 if (callback == nullptr) return;
799 ALOGV("asyncCodecFormatCallback %s", __func__);
800 callback->onCodecFormatChanged(metadataBs);
801}
802
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800803
804StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
805 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
806}
807
808StreamInHalHidl::~StreamInHalHidl() {
809 if (mStream != 0) {
810 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800811 }
812 if (mEfGroup) {
813 EventFlag::deleteEventFlag(&mEfGroup);
814 }
815}
816
817status_t StreamInHalHidl::getFrameSize(size_t *size) {
818 if (mStream == 0) return NO_INIT;
819 return processReturn("getFrameSize", mStream->getFrameSize(), size);
820}
821
822status_t StreamInHalHidl::setGain(float gain) {
823 if (mStream == 0) return NO_INIT;
824 return processReturn("setGain", mStream->setGain(gain));
825}
826
827status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
828 if (mStream == 0) return NO_INIT;
829 *read = 0;
830
831 if (bytes == 0 && !mDataMQ) {
832 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
833 return OK;
834 }
835
836 status_t status;
837 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
838 return status;
839 }
840
841 ReadParameters params;
842 params.command = ReadCommand::READ;
843 params.params.read = bytes;
844 status = callReaderThread(params, "read",
845 [&](const ReadStatus& readStatus) {
846 const size_t availToRead = mDataMQ->availableToRead();
847 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
848 ALOGE("data message queue read failed for \"read\"");
849 }
850 ALOGW_IF(availToRead != readStatus.reply.read,
851 "HAL read report inconsistent: mq = %d, status = %d",
852 (int32_t)availToRead, (int32_t)readStatus.reply.read);
853 *read = readStatus.reply.read;
854 });
855 mStreamPowerLog.log(buffer, *read);
856 return status;
857}
858
859status_t StreamInHalHidl::callReaderThread(
860 const ReadParameters& params, const char* cmdName,
861 StreamInHalHidl::ReaderCallback callback) {
862 if (!mCommandMQ->write(&params)) {
863 ALOGW("command message queue write failed");
864 return -EAGAIN;
865 }
866 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
867
868 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
869 uint32_t efState = 0;
870retry:
871 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
872 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
873 ReadStatus readStatus;
874 readStatus.retval = Result::NOT_INITIALIZED;
875 if (!mStatusMQ->read(&readStatus)) {
876 ALOGE("status message read failed for \"%s\"", cmdName);
877 }
878 if (readStatus.retval == Result::OK) {
879 ret = OK;
880 callback(readStatus);
881 } else {
882 ret = processReturn(cmdName, readStatus.retval);
883 }
884 return ret;
885 }
886 if (ret == -EAGAIN || ret == -EINTR) {
887 // Spurious wakeup. This normally retries no more than once.
888 goto retry;
889 }
890 return ret;
891}
892
893status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
894 std::unique_ptr<CommandMQ> tempCommandMQ;
895 std::unique_ptr<DataMQ> tempDataMQ;
896 std::unique_ptr<StatusMQ> tempStatusMQ;
897 Result retval;
898 pid_t halThreadPid, halThreadTid;
899 Return<void> ret = mStream->prepareForReading(
900 1, bufferSize,
901 [&](Result r,
902 const CommandMQ::Descriptor& commandMQ,
903 const DataMQ::Descriptor& dataMQ,
904 const StatusMQ::Descriptor& statusMQ,
905 const ThreadInfo& halThreadInfo) {
906 retval = r;
907 if (retval == Result::OK) {
908 tempCommandMQ.reset(new CommandMQ(commandMQ));
909 tempDataMQ.reset(new DataMQ(dataMQ));
910 tempStatusMQ.reset(new StatusMQ(statusMQ));
911 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
912 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
913 }
914 halThreadPid = halThreadInfo.pid;
915 halThreadTid = halThreadInfo.tid;
916 }
917 });
918 if (!ret.isOk() || retval != Result::OK) {
919 return processReturn("prepareForReading", ret, retval);
920 }
921 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
922 !tempDataMQ || !tempDataMQ->isValid() ||
923 !tempStatusMQ || !tempStatusMQ->isValid() ||
924 !mEfGroup) {
925 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
926 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
927 "Command message queue for writing is invalid");
928 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
929 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
930 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
931 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
932 "Status message queue for reading is invalid");
933 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
934 return NO_INIT;
935 }
936 requestHalThreadPriority(halThreadPid, halThreadTid);
937
938 mCommandMQ = std::move(tempCommandMQ);
939 mDataMQ = std::move(tempDataMQ);
940 mStatusMQ = std::move(tempStatusMQ);
941 mReaderClient = gettid();
942 return OK;
943}
944
945status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
946 if (mStream == 0) return NO_INIT;
947 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
948}
949
950status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
951 if (mStream == 0) return NO_INIT;
952 if (mReaderClient == gettid() && mCommandMQ) {
953 ReadParameters params;
954 params.command = ReadCommand::GET_CAPTURE_POSITION;
955 return callReaderThread(params, "getCapturePosition",
956 [&](const ReadStatus& readStatus) {
957 *frames = readStatus.reply.capturePosition.frames;
958 *time = readStatus.reply.capturePosition.time;
959 });
960 } else {
961 Result retval;
962 Return<void> ret = mStream->getCapturePosition(
963 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
964 retval = r;
965 if (retval == Result::OK) {
966 *frames = hidlFrames;
967 *time = hidlTime;
968 }
969 });
970 return processReturn("getCapturePosition", ret, retval);
971 }
972}
973
Kevin Rocard070e7512018-05-22 09:29:13 -0700974#if MAJOR_VERSION == 2
975status_t StreamInHalHidl::getActiveMicrophones(
976 std::vector<media::MicrophoneInfo> *microphones __unused) {
977 if (mStream == 0) return NO_INIT;
978 return INVALID_OPERATION;
979}
980
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800981status_t StreamInHalHidl::updateSinkMetadata(
982 const StreamInHalInterface::SinkMetadata& /* sinkMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700983 // Audio HAL V2.0 does not support propagating sink metadata
984 return INVALID_OPERATION;
985}
986
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800987#elif MAJOR_VERSION >= 4
jiabin9ff780e2018-03-19 18:19:52 -0700988status_t StreamInHalHidl::getActiveMicrophones(
989 std::vector<media::MicrophoneInfo> *microphonesInfo) {
990 if (!mStream) return NO_INIT;
991 Result retval;
992 Return<void> ret = mStream->getActiveMicrophones(
993 [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
994 retval = r;
995 for (size_t k = 0; k < micArrayHal.size(); k++) {
996 audio_microphone_characteristic_t dst;
997 // convert
998 microphoneInfoToHal(micArrayHal[k], &dst);
999 media::MicrophoneInfo microphone = media::MicrophoneInfo(dst);
1000 microphonesInfo->push_back(microphone);
1001 }
1002 });
1003 return processReturn("getActiveMicrophones", ret, retval);
1004}
1005
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001006status_t StreamInHalHidl::updateSinkMetadata(const
1007 StreamInHalInterface::SinkMetadata& sinkMetadata) {
1008 CPP_VERSION::SinkMetadata halMetadata = {
Kevin Rocarda8975a72018-03-27 10:16:52 -07001009 .tracks = transformToHidlVec(sinkMetadata.tracks,
Eric Laurent94579172020-11-20 18:41:04 +01001010 [](const record_track_metadata_v7& metadata) -> RecordTrackMetadata {
1011 RecordTrackMetadata halTrackMetadata = {
1012 .source=static_cast<AudioSource>(metadata.base.source),
1013 .gain=metadata.base.gain,
Kevin Rocarda8975a72018-03-27 10:16:52 -07001014 };
Eric Laurent94579172020-11-20 18:41:04 +01001015#if MAJOR_VERSION >= 7
1016 HidlUtils::audioChannelMaskFromHal(metadata.channel_mask, true /*isInput*/,
1017 &halTrackMetadata.channelMask);
1018 std::istringstream tags{metadata.tags};
1019 std::string tag;
1020 while (std::getline(tags, tag, HidlUtils::sAudioTagSeparator)) {
1021 if (!tag.empty()) {
1022 halTrackMetadata.tags.push_back(tag);
1023 }
1024 }
1025#endif
1026 return halTrackMetadata;
Kevin Rocarda8975a72018-03-27 10:16:52 -07001027 })};
1028 return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(halMetadata));
1029}
Kevin Rocard070e7512018-05-22 09:29:13 -07001030#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -07001031
Paul McLean03a6e6a2018-12-04 10:54:13 -07001032#if MAJOR_VERSION < 5
Paul McLean12340082019-03-19 09:35:05 -06001033status_t StreamInHalHidl::setPreferredMicrophoneDirection(
1034 audio_microphone_direction_t direction __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001035 if (mStream == 0) return NO_INIT;
1036 return INVALID_OPERATION;
1037}
1038
Paul McLean12340082019-03-19 09:35:05 -06001039status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001040 if (mStream == 0) return NO_INIT;
1041 return INVALID_OPERATION;
1042}
1043#else
Paul McLean12340082019-03-19 09:35:05 -06001044status_t StreamInHalHidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001045 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001046 return processReturn("setPreferredMicrophoneDirection",
1047 mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction)));
Paul McLean03a6e6a2018-12-04 10:54:13 -07001048}
1049
Paul McLean12340082019-03-19 09:35:05 -06001050status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001051 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001052 return processReturn("setPreferredMicrophoneFieldDimension",
Paul McLean03a6e6a2018-12-04 10:54:13 -07001053 mStream->setMicrophoneFieldDimension(zoom));
1054}
1055#endif
1056
Kevin Rocard070e7512018-05-22 09:29:13 -07001057} // namespace CPP_VERSION
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001058} // namespace android