blob: f4a4fe129565fbb440e36bbd780b729bc4dc73c2 [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 Naganovcc73ef02020-11-06 10:09:52 -080020#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 Naganovcc73ef02020-11-06 10:09:52 -080026#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 Naganovcc73ef02020-11-06 10:09:52 -080032#include "ParameterUtils.h"
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080033#include "StreamHalHidl.h"
34
Mikhail Naganovcc73ef02020-11-06 10:09:52 -080035using ::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 Naganovcc73ef02020-11-06 10:09:52 -080058 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 Naganovcc73ef02020-11-06 10:09:52 -080061 mStreamPowerLog.init(config.sample_rate, config.channel_mask, config.format);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080062 }
63}
64
65StreamHalHidl::~StreamHalHidl() {
66 mStream = nullptr;
67}
68
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080069status_t StreamHalHidl::getBufferSize(size_t *size) {
70 if (!mStream) return NO_INIT;
71 status_t status = processReturn("getBufferSize", mStream->getBufferSize(), size);
72 if (status == OK) {
73 mCachedBufferSize = *size;
74 }
75 return status;
76}
77
Mikhail Naganov560637e2021-03-31 22:40:13 +000078status_t StreamHalHidl::getAudioProperties(audio_config_base_t *configBase) {
79 *configBase = AUDIO_CONFIG_BASE_INITIALIZER;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080080 if (!mStream) return NO_INIT;
Mikhail Naganovcc73ef02020-11-06 10:09:52 -080081#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080082 Return<void> ret = mStream->getAudioProperties(
Kevin Rocardb9cfbf12018-02-23 19:11:06 -080083 [&](uint32_t sr, auto m, auto f) {
Mikhail Naganov560637e2021-03-31 22:40:13 +000084 configBase->sample_rate = sr;
85 configBase->channel_mask = static_cast<audio_channel_mask_t>(m);
86 configBase->format = static_cast<audio_format_t>(f);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080087 });
88 return processReturn("getAudioProperties", ret);
Mikhail Naganovcc73ef02020-11-06 10:09:52 -080089#else
90 Result retval;
91 status_t conversionStatus = BAD_VALUE;
Mikhail Naganovcc73ef02020-11-06 10:09:52 -080092 Return<void> ret = mStream->getAudioProperties(
93 [&](Result r, const AudioConfigBase& config) {
94 retval = r;
95 if (retval == Result::OK) {
Mikhail Naganov560637e2021-03-31 22:40:13 +000096 conversionStatus = HidlUtils::audioConfigBaseToHal(config, configBase);
Mikhail Naganovcc73ef02020-11-06 10:09:52 -080097 }
98 });
99 if (status_t status = processReturn("getAudioProperties", ret, retval); status == NO_ERROR) {
Mikhail Naganovcc73ef02020-11-06 10:09:52 -0800100 return conversionStatus;
101 } else {
102 return status;
103 }
104#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800105}
106
107status_t StreamHalHidl::setParameters(const String8& kvPairs) {
108 if (!mStream) return NO_INIT;
109 hidl_vec<ParameterValue> hidlParams;
110 status_t status = parametersFromHal(kvPairs, &hidlParams);
111 if (status != OK) return status;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800112 return processReturn("setParameters",
Dean Wheatley7b417a22019-01-31 20:39:42 +1100113 utils::setParameters(mStream, {} /* context */, hidlParams));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800114}
115
116status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
117 values->clear();
118 if (!mStream) return NO_INIT;
119 hidl_vec<hidl_string> hidlKeys;
120 status_t status = keysFromHal(keys, &hidlKeys);
121 if (status != OK) return status;
122 Result retval;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800123 Return<void> ret = utils::getParameters(
124 mStream,
125 {} /* context */,
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800126 hidlKeys,
127 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
128 retval = r;
129 if (retval == Result::OK) {
130 parametersToHal(parameters, values);
131 }
132 });
133 return processReturn("getParameters", ret, retval);
134}
135
136status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
137 if (!mStream) return NO_INIT;
138 return processReturn("addEffect", mStream->addEffect(
139 static_cast<EffectHalHidl*>(effect.get())->effectId()));
140}
141
142status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
143 if (!mStream) return NO_INIT;
144 return processReturn("removeEffect", mStream->removeEffect(
145 static_cast<EffectHalHidl*>(effect.get())->effectId()));
146}
147
148status_t StreamHalHidl::standby() {
149 if (!mStream) return NO_INIT;
150 return processReturn("standby", mStream->standby());
151}
152
153status_t StreamHalHidl::dump(int fd) {
154 if (!mStream) return NO_INIT;
155 native_handle_t* hidlHandle = native_handle_create(1, 0);
156 hidlHandle->data[0] = fd;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800157 Return<void> ret = mStream->debug(hidlHandle, {} /* options */);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800158 native_handle_delete(hidlHandle);
159 mStreamPowerLog.dump(fd);
160 return processReturn("dump", ret);
161}
162
163status_t StreamHalHidl::start() {
164 if (!mStream) return NO_INIT;
165 return processReturn("start", mStream->start());
166}
167
168status_t StreamHalHidl::stop() {
169 if (!mStream) return NO_INIT;
170 return processReturn("stop", mStream->stop());
171}
172
173status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
174 struct audio_mmap_buffer_info *info) {
175 Result retval;
176 Return<void> ret = mStream->createMmapBuffer(
177 minSizeFrames,
178 [&](Result r, const MmapBufferInfo& hidlInfo) {
179 retval = r;
180 if (retval == Result::OK) {
181 const native_handle *handle = hidlInfo.sharedMemory.handle();
182 if (handle->numFds > 0) {
183 info->shared_memory_fd = handle->data[0];
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800184#if MAJOR_VERSION >= 4
Kevin Rocard734334f2018-07-12 19:37:41 -0700185 info->flags = audio_mmap_buffer_flag(hidlInfo.flags);
186#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800187 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
Kevin Rocard734334f2018-07-12 19:37:41 -0700188 // Negative buffer size frame was a hack in O and P to
189 // indicate that the buffer is shareable to applications
190 if (info->buffer_size_frames < 0) {
191 info->buffer_size_frames *= -1;
192 info->flags = audio_mmap_buffer_flag(
193 info->flags | AUDIO_MMAP_APPLICATION_SHAREABLE);
194 }
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800195 info->burst_size_frames = hidlInfo.burstSizeFrames;
196 // info->shared_memory_address is not needed in HIDL context
197 info->shared_memory_address = NULL;
198 } else {
199 retval = Result::NOT_INITIALIZED;
200 }
201 }
202 });
203 return processReturn("createMmapBuffer", ret, retval);
204}
205
206status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
207 Result retval;
208 Return<void> ret = mStream->getMmapPosition(
209 [&](Result r, const MmapPosition& hidlPosition) {
210 retval = r;
211 if (retval == Result::OK) {
212 position->time_nanoseconds = hidlPosition.timeNanoseconds;
213 position->position_frames = hidlPosition.positionFrames;
214 }
215 });
216 return processReturn("getMmapPosition", ret, retval);
217}
218
219status_t StreamHalHidl::setHalThreadPriority(int priority) {
220 mHalThreadPriority = priority;
221 return OK;
222}
223
224status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
225 if (mCachedBufferSize != 0) {
226 *size = mCachedBufferSize;
227 return OK;
228 }
229 return getBufferSize(size);
230}
231
Mikhail Naganovcc73ef02020-11-06 10:09:52 -0800232status_t StreamHalHidl::getHalPid(pid_t *pid) {
233 using ::android::hidl::base::V1_0::DebugInfo;
234 using ::android::hidl::manager::V1_0::IServiceManager;
235
236 DebugInfo debugInfo;
237 auto ret = mStream->getDebugInfo([&] (const auto &info) {
238 debugInfo = info;
239 });
240 if (!ret.isOk()) {
241 return INVALID_OPERATION;
242 }
243 if (debugInfo.pid != (int)IServiceManager::PidConstant::NO_PID) {
244 *pid = debugInfo.pid;
245 return NO_ERROR;
246 }
247 return NAME_NOT_FOUND;
248}
249
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800250bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
251 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
252 return true;
253 }
254 int err = requestPriority(
255 threadPid, threadId,
256 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
257 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
258 mHalThreadPriority, threadPid, threadId, err);
259 // Audio will still work, but latency will be higher and sometimes unacceptable.
260 return err == 0;
261}
262
263namespace {
264
265/* Notes on callback ownership.
266
267This is how (Hw)Binder ownership model looks like. The server implementation
268is owned by Binder framework (via sp<>). Proxies are owned by clients.
269When the last proxy disappears, Binder framework releases the server impl.
270
271Thus, it is not needed to keep any references to StreamOutCallback (this is
272the server impl) -- it will live as long as HAL server holds a strong ref to
273IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
274from the destructor of StreamOutHalHidl.
275
276The callback only keeps a weak reference to the stream. The stream is owned
277by AudioFlinger.
278
279*/
280
281struct StreamOutCallback : public IStreamOutCallback {
282 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
283
284 // IStreamOutCallback implementation
285 Return<void> onWriteReady() override {
286 sp<StreamOutHalHidl> stream = mStream.promote();
287 if (stream != 0) {
288 stream->onWriteReady();
289 }
290 return Void();
291 }
292
293 Return<void> onDrainReady() override {
294 sp<StreamOutHalHidl> stream = mStream.promote();
295 if (stream != 0) {
296 stream->onDrainReady();
297 }
298 return Void();
299 }
300
301 Return<void> onError() override {
302 sp<StreamOutHalHidl> stream = mStream.promote();
303 if (stream != 0) {
304 stream->onError();
305 }
306 return Void();
307 }
308
309 private:
310 wp<StreamOutHalHidl> mStream;
311};
312
313} // namespace
314
315StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
316 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
317}
318
319StreamOutHalHidl::~StreamOutHalHidl() {
320 if (mStream != 0) {
321 if (mCallback.unsafe_get()) {
322 processReturn("clearCallback", mStream->clearCallback());
323 }
jiabinf6eb4c32020-02-25 14:06:25 -0800324#if MAJOR_VERSION >= 6
325 if (mEventCallback.unsafe_get() != nullptr) {
326 processReturn("setEventCallback",
327 mStream->setEventCallback(nullptr));
328 }
329#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800330 processReturn("close", mStream->close());
331 mStream.clear();
332 }
333 mCallback.clear();
jiabinf6eb4c32020-02-25 14:06:25 -0800334 mEventCallback.clear();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800335 hardware::IPCThreadState::self()->flushCommands();
336 if (mEfGroup) {
337 EventFlag::deleteEventFlag(&mEfGroup);
338 }
339}
340
341status_t StreamOutHalHidl::getFrameSize(size_t *size) {
342 if (mStream == 0) return NO_INIT;
343 return processReturn("getFrameSize", mStream->getFrameSize(), size);
344}
345
346status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
347 if (mStream == 0) return NO_INIT;
348 if (mWriterClient == gettid() && mCommandMQ) {
349 return callWriterThread(
350 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
351 [&](const WriteStatus& writeStatus) {
352 *latency = writeStatus.reply.latencyMs;
353 });
354 } else {
355 return processReturn("getLatency", mStream->getLatency(), latency);
356 }
357}
358
359status_t StreamOutHalHidl::setVolume(float left, float right) {
360 if (mStream == 0) return NO_INIT;
361 return processReturn("setVolume", mStream->setVolume(left, right));
362}
363
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800364#if MAJOR_VERSION == 2
365status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
366 if (mStream == 0) return NO_INIT;
367 std::vector<ParameterValue> parameters;
368 String8 halParameters;
369 parameters.push_back({AudioParameter::keyPresentationId, std::to_string(presentationId)});
370 parameters.push_back({AudioParameter::keyProgramId, std::to_string(programId)});
371 parametersToHal(hidl_vec<ParameterValue>(parameters), &halParameters);
372 return setParameters(halParameters);
373}
Kevin Rocard1cf6b4d2018-11-20 18:05:44 -0800374#elif MAJOR_VERSION >= 4
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800375status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
376 if (mStream == 0) return NO_INIT;
377 return processReturn("selectPresentation",
378 mStream->selectPresentation(presentationId, programId));
379}
380#endif
381
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800382status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
383 if (mStream == 0) return NO_INIT;
384 *written = 0;
385
386 if (bytes == 0 && !mDataMQ) {
387 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
388 ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes");
389 return OK;
390 }
391
392 status_t status;
393 if (!mDataMQ) {
394 // In case if playback starts close to the end of a compressed track, the bytes
395 // that need to be written is less than the actual buffer size. Need to use
396 // full buffer size for the MQ since otherwise after seeking back to the middle
397 // data will be truncated.
398 size_t bufferSize;
399 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
400 return status;
401 }
402 if (bytes > bufferSize) bufferSize = bytes;
403 if ((status = prepareForWriting(bufferSize)) != OK) {
404 return status;
405 }
406 }
407
408 status = callWriterThread(
409 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
410 [&] (const WriteStatus& writeStatus) {
411 *written = writeStatus.reply.written;
412 // Diagnostics of the cause of b/35813113.
413 ALOGE_IF(*written > bytes,
414 "hal reports more bytes written than asked for: %lld > %lld",
415 (long long)*written, (long long)bytes);
416 });
417 mStreamPowerLog.log(buffer, *written);
418 return status;
419}
420
421status_t StreamOutHalHidl::callWriterThread(
422 WriteCommand cmd, const char* cmdName,
423 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
424 if (!mCommandMQ->write(&cmd)) {
425 ALOGE("command message queue write failed for \"%s\"", cmdName);
426 return -EAGAIN;
427 }
428 if (data != nullptr) {
429 size_t availableToWrite = mDataMQ->availableToWrite();
430 if (dataSize > availableToWrite) {
431 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
432 (long long)dataSize, (long long)availableToWrite);
433 dataSize = availableToWrite;
434 }
435 if (!mDataMQ->write(data, dataSize)) {
436 ALOGE("data message queue write failed for \"%s\"", cmdName);
437 }
438 }
439 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
440
441 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
442 uint32_t efState = 0;
443retry:
444 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
445 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
446 WriteStatus writeStatus;
447 writeStatus.retval = Result::NOT_INITIALIZED;
448 if (!mStatusMQ->read(&writeStatus)) {
449 ALOGE("status message read failed for \"%s\"", cmdName);
450 }
451 if (writeStatus.retval == Result::OK) {
452 ret = OK;
453 callback(writeStatus);
454 } else {
455 ret = processReturn(cmdName, writeStatus.retval);
456 }
457 return ret;
458 }
459 if (ret == -EAGAIN || ret == -EINTR) {
460 // Spurious wakeup. This normally retries no more than once.
461 goto retry;
462 }
463 return ret;
464}
465
466status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
467 std::unique_ptr<CommandMQ> tempCommandMQ;
468 std::unique_ptr<DataMQ> tempDataMQ;
469 std::unique_ptr<StatusMQ> tempStatusMQ;
470 Result retval;
471 pid_t halThreadPid, halThreadTid;
472 Return<void> ret = mStream->prepareForWriting(
473 1, bufferSize,
474 [&](Result r,
475 const CommandMQ::Descriptor& commandMQ,
476 const DataMQ::Descriptor& dataMQ,
477 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganovcc73ef02020-11-06 10:09:52 -0800478 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800479 retval = r;
480 if (retval == Result::OK) {
481 tempCommandMQ.reset(new CommandMQ(commandMQ));
482 tempDataMQ.reset(new DataMQ(dataMQ));
483 tempStatusMQ.reset(new StatusMQ(statusMQ));
484 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
485 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
486 }
Mikhail Naganovcc73ef02020-11-06 10:09:52 -0800487#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800488 halThreadPid = halThreadInfo.pid;
489 halThreadTid = halThreadInfo.tid;
Mikhail Naganovcc73ef02020-11-06 10:09:52 -0800490#else
491 halThreadTid = halThreadInfo;
492#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800493 }
494 });
495 if (!ret.isOk() || retval != Result::OK) {
496 return processReturn("prepareForWriting", ret, retval);
497 }
498 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
499 !tempDataMQ || !tempDataMQ->isValid() ||
500 !tempStatusMQ || !tempStatusMQ->isValid() ||
501 !mEfGroup) {
502 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
503 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
504 "Command message queue for writing is invalid");
505 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
506 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
507 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
508 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
509 "Status message queue for writing is invalid");
510 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
511 return NO_INIT;
512 }
Mikhail Naganovcc73ef02020-11-06 10:09:52 -0800513#if MAJOR_VERSION >= 7
514 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
515 return status;
516 }
517#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800518 requestHalThreadPriority(halThreadPid, halThreadTid);
519
520 mCommandMQ = std::move(tempCommandMQ);
521 mDataMQ = std::move(tempDataMQ);
522 mStatusMQ = std::move(tempStatusMQ);
523 mWriterClient = gettid();
524 return OK;
525}
526
527status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
528 if (mStream == 0) return NO_INIT;
529 Result retval;
530 Return<void> ret = mStream->getRenderPosition(
531 [&](Result r, uint32_t d) {
532 retval = r;
533 if (retval == Result::OK) {
534 *dspFrames = d;
535 }
536 });
537 return processReturn("getRenderPosition", ret, retval);
538}
539
540status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
541 if (mStream == 0) return NO_INIT;
542 Result retval;
543 Return<void> ret = mStream->getNextWriteTimestamp(
544 [&](Result r, int64_t t) {
545 retval = r;
546 if (retval == Result::OK) {
547 *timestamp = t;
548 }
549 });
550 return processReturn("getRenderPosition", ret, retval);
551}
552
553status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
554 if (mStream == 0) return NO_INIT;
555 status_t status = processReturn(
556 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
557 if (status == OK) {
558 mCallback = callback;
559 }
560 return status;
561}
562
563status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
564 if (mStream == 0) return NO_INIT;
565 Return<void> ret = mStream->supportsPauseAndResume(
566 [&](bool p, bool r) {
567 *supportsPause = p;
568 *supportsResume = r;
569 });
570 return processReturn("supportsPauseAndResume", ret);
571}
572
573status_t StreamOutHalHidl::pause() {
574 if (mStream == 0) return NO_INIT;
575 return processReturn("pause", mStream->pause());
576}
577
578status_t StreamOutHalHidl::resume() {
579 if (mStream == 0) return NO_INIT;
580 return processReturn("pause", mStream->resume());
581}
582
583status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
584 if (mStream == 0) return NO_INIT;
585 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
586}
587
588status_t StreamOutHalHidl::drain(bool earlyNotify) {
589 if (mStream == 0) return NO_INIT;
590 return processReturn(
591 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
592}
593
594status_t StreamOutHalHidl::flush() {
595 if (mStream == 0) return NO_INIT;
596 return processReturn("pause", mStream->flush());
597}
598
599status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
600 if (mStream == 0) return NO_INIT;
601 if (mWriterClient == gettid() && mCommandMQ) {
602 return callWriterThread(
603 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
604 [&](const WriteStatus& writeStatus) {
605 *frames = writeStatus.reply.presentationPosition.frames;
606 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
607 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
608 });
609 } else {
610 Result retval;
611 Return<void> ret = mStream->getPresentationPosition(
612 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
613 retval = r;
614 if (retval == Result::OK) {
615 *frames = hidlFrames;
616 timestamp->tv_sec = hidlTimeStamp.tvSec;
617 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
618 }
619 });
620 return processReturn("getPresentationPosition", ret, retval);
621 }
622}
623
Kevin Rocard070e7512018-05-22 09:29:13 -0700624#if MAJOR_VERSION == 2
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800625status_t StreamOutHalHidl::updateSourceMetadata(
626 const StreamOutHalInterface::SourceMetadata& /* sourceMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700627 // Audio HAL V2.0 does not support propagating source metadata
628 return INVALID_OPERATION;
629}
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800630#elif MAJOR_VERSION >= 4
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800631status_t StreamOutHalHidl::updateSourceMetadata(
632 const StreamOutHalInterface::SourceMetadata& sourceMetadata) {
Mikhail Naganovcc73ef02020-11-06 10:09:52 -0800633 CPP_VERSION::SourceMetadata hidlMetadata;
634 if (status_t status = CoreUtils::sourceMetadataFromHalV7(
635 sourceMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
636 status != OK) {
637 return status;
638 }
639 return processReturn("updateSourceMetadata", mStream->updateSourceMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -0700640}
Kevin Rocard070e7512018-05-22 09:29:13 -0700641#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700642
jiabinf6eb4c32020-02-25 14:06:25 -0800643#if MAJOR_VERSION < 6
Kuowei Li3bea3a42020-08-13 14:44:25 +0800644status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode __unused) {
645 return INVALID_OPERATION;
646}
647
648status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode __unused) {
649 return INVALID_OPERATION;
650}
651
652status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB __unused) {
653 return INVALID_OPERATION;
654}
655
656status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB __unused) {
657 return INVALID_OPERATION;
658}
659
660status_t StreamOutHalHidl::getPlaybackRateParameters(
661 audio_playback_rate_t* playbackRate __unused) {
662 return INVALID_OPERATION;
663}
664
665status_t StreamOutHalHidl::setPlaybackRateParameters(
666 const audio_playback_rate_t& playbackRate __unused) {
667 return INVALID_OPERATION;
668}
669
jiabinf6eb4c32020-02-25 14:06:25 -0800670status_t StreamOutHalHidl::setEventCallback(
671 const sp<StreamOutHalInterfaceEventCallback>& callback __unused) {
672 // Codec format callback is supported starting from audio HAL V6.0
673 return INVALID_OPERATION;
674}
675#else
676
Kuowei Li3bea3a42020-08-13 14:44:25 +0800677status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode) {
678 if (mStream == 0) return NO_INIT;
679 Result retval;
680 Return<void> ret = mStream->getDualMonoMode(
681 [&](Result r, DualMonoMode hidlMode) {
682 retval = r;
683 if (retval == Result::OK) {
684 *mode = static_cast<audio_dual_mono_mode_t>(hidlMode);
685 }
686 });
687 return processReturn("getDualMonoMode", ret, retval);
688}
689
690status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode) {
691 if (mStream == 0) return NO_INIT;
692 return processReturn(
693 "setDualMonoMode", mStream->setDualMonoMode(static_cast<DualMonoMode>(mode)));
694}
695
696status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB) {
697 if (mStream == 0) return NO_INIT;
698 Result retval;
699 Return<void> ret = mStream->getAudioDescriptionMixLevel(
700 [&](Result r, float hidlLeveldB) {
701 retval = r;
702 if (retval == Result::OK) {
703 *leveldB = hidlLeveldB;
704 }
705 });
706 return processReturn("getAudioDescriptionMixLevel", ret, retval);
707}
708
709status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB) {
710 if (mStream == 0) return NO_INIT;
711 return processReturn(
712 "setAudioDescriptionMixLevel", mStream->setAudioDescriptionMixLevel(leveldB));
713}
714
715status_t StreamOutHalHidl::getPlaybackRateParameters(audio_playback_rate_t* playbackRate) {
716 if (mStream == 0) return NO_INIT;
717 Result retval;
718 Return<void> ret = mStream->getPlaybackRateParameters(
719 [&](Result r, PlaybackRate hidlPlaybackRate) {
720 retval = r;
721 if (retval == Result::OK) {
722 playbackRate->mSpeed = hidlPlaybackRate.speed;
723 playbackRate->mPitch = hidlPlaybackRate.pitch;
724 playbackRate->mStretchMode =
725 static_cast<audio_timestretch_stretch_mode_t>(
726 hidlPlaybackRate.timestretchMode);
727 playbackRate->mFallbackMode =
728 static_cast<audio_timestretch_fallback_mode_t>(
729 hidlPlaybackRate.fallbackMode);
730 }
731 });
732 return processReturn("getPlaybackRateParameters", ret, retval);
733}
734
735status_t StreamOutHalHidl::setPlaybackRateParameters(const audio_playback_rate_t& playbackRate) {
736 if (mStream == 0) return NO_INIT;
737 return processReturn(
738 "setPlaybackRateParameters", mStream->setPlaybackRateParameters(
739 PlaybackRate{playbackRate.mSpeed, playbackRate.mPitch,
740 static_cast<TimestretchMode>(playbackRate.mStretchMode),
741 static_cast<TimestretchFallbackMode>(playbackRate.mFallbackMode)}));
742}
743
jiabinf6eb4c32020-02-25 14:06:25 -0800744#include PATH(android/hardware/audio/FILE_VERSION/IStreamOutEventCallback.h)
745
746namespace {
747
748struct StreamOutEventCallback : public IStreamOutEventCallback {
749 StreamOutEventCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
750
751 // IStreamOutEventCallback implementation
752 Return<void> onCodecFormatChanged(
753 const android::hardware::hidl_vec<uint8_t>& audioMetadata) override {
754 sp<StreamOutHalHidl> stream = mStream.promote();
755 if (stream != nullptr) {
756 std::basic_string<uint8_t> metadataBs(audioMetadata.begin(), audioMetadata.end());
757 stream->onCodecFormatChanged(metadataBs);
758 }
759 return Void();
760 }
761
762 private:
763 wp<StreamOutHalHidl> mStream;
764};
765
766} // namespace
767
768status_t StreamOutHalHidl::setEventCallback(
769 const sp<StreamOutHalInterfaceEventCallback>& callback) {
770 if (mStream == nullptr) return NO_INIT;
771 mEventCallback = callback;
772 status_t status = processReturn(
773 "setEventCallback",
774 mStream->setEventCallback(
775 callback.get() == nullptr ? nullptr : new StreamOutEventCallback(this)));
776 return status;
777}
778#endif
779
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800780void StreamOutHalHidl::onWriteReady() {
781 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
782 if (callback == 0) return;
783 ALOGV("asyncCallback onWriteReady");
784 callback->onWriteReady();
785}
786
787void StreamOutHalHidl::onDrainReady() {
788 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
789 if (callback == 0) return;
790 ALOGV("asyncCallback onDrainReady");
791 callback->onDrainReady();
792}
793
794void StreamOutHalHidl::onError() {
795 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
796 if (callback == 0) return;
797 ALOGV("asyncCallback onError");
798 callback->onError();
799}
800
jiabinf6eb4c32020-02-25 14:06:25 -0800801void StreamOutHalHidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) {
802 sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.promote();
803 if (callback == nullptr) return;
804 ALOGV("asyncCodecFormatCallback %s", __func__);
805 callback->onCodecFormatChanged(metadataBs);
806}
807
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800808
809StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
810 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
811}
812
813StreamInHalHidl::~StreamInHalHidl() {
814 if (mStream != 0) {
815 processReturn("close", mStream->close());
816 mStream.clear();
817 hardware::IPCThreadState::self()->flushCommands();
818 }
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 Naganovcc73ef02020-11-06 10:09:52 -0800912 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 Naganovcc73ef02020-11-06 10:09:52 -0800921#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800922 halThreadPid = halThreadInfo.pid;
923 halThreadTid = halThreadInfo.tid;
Mikhail Naganovcc73ef02020-11-06 10:09:52 -0800924#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 Naganovcc73ef02020-11-06 10:09:52 -0800947#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 Naganovcc73ef02020-11-06 10:09:52 -08001014 (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 Naganovcc73ef02020-11-06 10:09:52 -08001024 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