blob: 6da8bbd7dfd144e632fad60c79c5e0a694ca9078 [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() && */
60 StreamHalHidl::getAudioProperties(
61 &config.sample_rate, &config.channel_mask, &config.format) == NO_ERROR) {
62 mStreamPowerLog.init(config.sample_rate, config.channel_mask, config.format);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080063 }
64}
65
66StreamHalHidl::~StreamHalHidl() {
67 mStream = nullptr;
68}
69
Mikhail Naganovcc73ef02020-11-06 10:09:52 -080070// Note: this method will be removed
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080071status_t StreamHalHidl::getSampleRate(uint32_t *rate) {
Mikhail Naganovcc73ef02020-11-06 10:09:52 -080072 audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
73 status_t status = getAudioProperties(&config.sample_rate, &config.channel_mask, &config.format);
74 *rate = config.sample_rate;
75 return status;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080076}
77
78status_t StreamHalHidl::getBufferSize(size_t *size) {
79 if (!mStream) return NO_INIT;
80 status_t status = processReturn("getBufferSize", mStream->getBufferSize(), size);
81 if (status == OK) {
82 mCachedBufferSize = *size;
83 }
84 return status;
85}
86
Mikhail Naganovcc73ef02020-11-06 10:09:52 -080087// Note: this method will be removed
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080088status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) {
Mikhail Naganovcc73ef02020-11-06 10:09:52 -080089 audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
90 status_t status = getAudioProperties(&config.sample_rate, &config.channel_mask, &config.format);
91 *mask = config.channel_mask;
92 return status;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080093}
94
Mikhail Naganovcc73ef02020-11-06 10:09:52 -080095// Note: this method will be removed
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080096status_t StreamHalHidl::getFormat(audio_format_t *format) {
Mikhail Naganovcc73ef02020-11-06 10:09:52 -080097 audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
98 status_t status = getAudioProperties(&config.sample_rate, &config.channel_mask, &config.format);
99 *format = config.format;
100 return status;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800101}
102
103status_t StreamHalHidl::getAudioProperties(
104 uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) {
105 if (!mStream) return NO_INIT;
Mikhail Naganovcc73ef02020-11-06 10:09:52 -0800106#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800107 Return<void> ret = mStream->getAudioProperties(
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800108 [&](uint32_t sr, auto m, auto f) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800109 *sampleRate = sr;
110 *mask = static_cast<audio_channel_mask_t>(m);
111 *format = static_cast<audio_format_t>(f);
112 });
113 return processReturn("getAudioProperties", ret);
Mikhail Naganovcc73ef02020-11-06 10:09:52 -0800114#else
115 Result retval;
116 status_t conversionStatus = BAD_VALUE;
117 audio_config_base_t halConfig = AUDIO_CONFIG_BASE_INITIALIZER;
118 Return<void> ret = mStream->getAudioProperties(
119 [&](Result r, const AudioConfigBase& config) {
120 retval = r;
121 if (retval == Result::OK) {
122 conversionStatus = HidlUtils::audioConfigBaseToHal(config, &halConfig);
123 }
124 });
125 if (status_t status = processReturn("getAudioProperties", ret, retval); status == NO_ERROR) {
126 *sampleRate = halConfig.sample_rate;
127 *mask = halConfig.channel_mask;
128 *format = halConfig.format;
129 return conversionStatus;
130 } else {
131 return status;
132 }
133#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800134}
135
136status_t StreamHalHidl::setParameters(const String8& kvPairs) {
137 if (!mStream) return NO_INIT;
138 hidl_vec<ParameterValue> hidlParams;
139 status_t status = parametersFromHal(kvPairs, &hidlParams);
140 if (status != OK) return status;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800141 return processReturn("setParameters",
Dean Wheatley7b417a22019-01-31 20:39:42 +1100142 utils::setParameters(mStream, {} /* context */, hidlParams));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800143}
144
145status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
146 values->clear();
147 if (!mStream) return NO_INIT;
148 hidl_vec<hidl_string> hidlKeys;
149 status_t status = keysFromHal(keys, &hidlKeys);
150 if (status != OK) return status;
151 Result retval;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800152 Return<void> ret = utils::getParameters(
153 mStream,
154 {} /* context */,
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800155 hidlKeys,
156 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
157 retval = r;
158 if (retval == Result::OK) {
159 parametersToHal(parameters, values);
160 }
161 });
162 return processReturn("getParameters", ret, retval);
163}
164
165status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
166 if (!mStream) return NO_INIT;
167 return processReturn("addEffect", mStream->addEffect(
168 static_cast<EffectHalHidl*>(effect.get())->effectId()));
169}
170
171status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
172 if (!mStream) return NO_INIT;
173 return processReturn("removeEffect", mStream->removeEffect(
174 static_cast<EffectHalHidl*>(effect.get())->effectId()));
175}
176
177status_t StreamHalHidl::standby() {
178 if (!mStream) return NO_INIT;
179 return processReturn("standby", mStream->standby());
180}
181
182status_t StreamHalHidl::dump(int fd) {
183 if (!mStream) return NO_INIT;
184 native_handle_t* hidlHandle = native_handle_create(1, 0);
185 hidlHandle->data[0] = fd;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800186 Return<void> ret = mStream->debug(hidlHandle, {} /* options */);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800187 native_handle_delete(hidlHandle);
188 mStreamPowerLog.dump(fd);
189 return processReturn("dump", ret);
190}
191
192status_t StreamHalHidl::start() {
193 if (!mStream) return NO_INIT;
194 return processReturn("start", mStream->start());
195}
196
197status_t StreamHalHidl::stop() {
198 if (!mStream) return NO_INIT;
199 return processReturn("stop", mStream->stop());
200}
201
202status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
203 struct audio_mmap_buffer_info *info) {
204 Result retval;
205 Return<void> ret = mStream->createMmapBuffer(
206 minSizeFrames,
207 [&](Result r, const MmapBufferInfo& hidlInfo) {
208 retval = r;
209 if (retval == Result::OK) {
210 const native_handle *handle = hidlInfo.sharedMemory.handle();
211 if (handle->numFds > 0) {
212 info->shared_memory_fd = handle->data[0];
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800213#if MAJOR_VERSION >= 4
Kevin Rocard734334f2018-07-12 19:37:41 -0700214 info->flags = audio_mmap_buffer_flag(hidlInfo.flags);
215#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800216 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
Kevin Rocard734334f2018-07-12 19:37:41 -0700217 // Negative buffer size frame was a hack in O and P to
218 // indicate that the buffer is shareable to applications
219 if (info->buffer_size_frames < 0) {
220 info->buffer_size_frames *= -1;
221 info->flags = audio_mmap_buffer_flag(
222 info->flags | AUDIO_MMAP_APPLICATION_SHAREABLE);
223 }
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800224 info->burst_size_frames = hidlInfo.burstSizeFrames;
225 // info->shared_memory_address is not needed in HIDL context
226 info->shared_memory_address = NULL;
227 } else {
228 retval = Result::NOT_INITIALIZED;
229 }
230 }
231 });
232 return processReturn("createMmapBuffer", ret, retval);
233}
234
235status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
236 Result retval;
237 Return<void> ret = mStream->getMmapPosition(
238 [&](Result r, const MmapPosition& hidlPosition) {
239 retval = r;
240 if (retval == Result::OK) {
241 position->time_nanoseconds = hidlPosition.timeNanoseconds;
242 position->position_frames = hidlPosition.positionFrames;
243 }
244 });
245 return processReturn("getMmapPosition", ret, retval);
246}
247
248status_t StreamHalHidl::setHalThreadPriority(int priority) {
249 mHalThreadPriority = priority;
250 return OK;
251}
252
253status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
254 if (mCachedBufferSize != 0) {
255 *size = mCachedBufferSize;
256 return OK;
257 }
258 return getBufferSize(size);
259}
260
Mikhail Naganovcc73ef02020-11-06 10:09:52 -0800261status_t StreamHalHidl::getHalPid(pid_t *pid) {
262 using ::android::hidl::base::V1_0::DebugInfo;
263 using ::android::hidl::manager::V1_0::IServiceManager;
264
265 DebugInfo debugInfo;
266 auto ret = mStream->getDebugInfo([&] (const auto &info) {
267 debugInfo = info;
268 });
269 if (!ret.isOk()) {
270 return INVALID_OPERATION;
271 }
272 if (debugInfo.pid != (int)IServiceManager::PidConstant::NO_PID) {
273 *pid = debugInfo.pid;
274 return NO_ERROR;
275 }
276 return NAME_NOT_FOUND;
277}
278
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800279bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
280 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
281 return true;
282 }
283 int err = requestPriority(
284 threadPid, threadId,
285 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
286 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
287 mHalThreadPriority, threadPid, threadId, err);
288 // Audio will still work, but latency will be higher and sometimes unacceptable.
289 return err == 0;
290}
291
292namespace {
293
294/* Notes on callback ownership.
295
296This is how (Hw)Binder ownership model looks like. The server implementation
297is owned by Binder framework (via sp<>). Proxies are owned by clients.
298When the last proxy disappears, Binder framework releases the server impl.
299
300Thus, it is not needed to keep any references to StreamOutCallback (this is
301the server impl) -- it will live as long as HAL server holds a strong ref to
302IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
303from the destructor of StreamOutHalHidl.
304
305The callback only keeps a weak reference to the stream. The stream is owned
306by AudioFlinger.
307
308*/
309
310struct StreamOutCallback : public IStreamOutCallback {
311 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
312
313 // IStreamOutCallback implementation
314 Return<void> onWriteReady() override {
315 sp<StreamOutHalHidl> stream = mStream.promote();
316 if (stream != 0) {
317 stream->onWriteReady();
318 }
319 return Void();
320 }
321
322 Return<void> onDrainReady() override {
323 sp<StreamOutHalHidl> stream = mStream.promote();
324 if (stream != 0) {
325 stream->onDrainReady();
326 }
327 return Void();
328 }
329
330 Return<void> onError() override {
331 sp<StreamOutHalHidl> stream = mStream.promote();
332 if (stream != 0) {
333 stream->onError();
334 }
335 return Void();
336 }
337
338 private:
339 wp<StreamOutHalHidl> mStream;
340};
341
342} // namespace
343
344StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
345 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
346}
347
348StreamOutHalHidl::~StreamOutHalHidl() {
349 if (mStream != 0) {
350 if (mCallback.unsafe_get()) {
351 processReturn("clearCallback", mStream->clearCallback());
352 }
jiabinf6eb4c32020-02-25 14:06:25 -0800353#if MAJOR_VERSION >= 6
354 if (mEventCallback.unsafe_get() != nullptr) {
355 processReturn("setEventCallback",
356 mStream->setEventCallback(nullptr));
357 }
358#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800359 processReturn("close", mStream->close());
360 mStream.clear();
361 }
362 mCallback.clear();
jiabinf6eb4c32020-02-25 14:06:25 -0800363 mEventCallback.clear();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800364 hardware::IPCThreadState::self()->flushCommands();
365 if (mEfGroup) {
366 EventFlag::deleteEventFlag(&mEfGroup);
367 }
368}
369
370status_t StreamOutHalHidl::getFrameSize(size_t *size) {
371 if (mStream == 0) return NO_INIT;
372 return processReturn("getFrameSize", mStream->getFrameSize(), size);
373}
374
375status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
376 if (mStream == 0) return NO_INIT;
377 if (mWriterClient == gettid() && mCommandMQ) {
378 return callWriterThread(
379 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
380 [&](const WriteStatus& writeStatus) {
381 *latency = writeStatus.reply.latencyMs;
382 });
383 } else {
384 return processReturn("getLatency", mStream->getLatency(), latency);
385 }
386}
387
388status_t StreamOutHalHidl::setVolume(float left, float right) {
389 if (mStream == 0) return NO_INIT;
390 return processReturn("setVolume", mStream->setVolume(left, right));
391}
392
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800393#if MAJOR_VERSION == 2
394status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
395 if (mStream == 0) return NO_INIT;
396 std::vector<ParameterValue> parameters;
397 String8 halParameters;
398 parameters.push_back({AudioParameter::keyPresentationId, std::to_string(presentationId)});
399 parameters.push_back({AudioParameter::keyProgramId, std::to_string(programId)});
400 parametersToHal(hidl_vec<ParameterValue>(parameters), &halParameters);
401 return setParameters(halParameters);
402}
Kevin Rocard1cf6b4d2018-11-20 18:05:44 -0800403#elif MAJOR_VERSION >= 4
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800404status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) {
405 if (mStream == 0) return NO_INIT;
406 return processReturn("selectPresentation",
407 mStream->selectPresentation(presentationId, programId));
408}
409#endif
410
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800411status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
412 if (mStream == 0) return NO_INIT;
413 *written = 0;
414
415 if (bytes == 0 && !mDataMQ) {
416 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
417 ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes");
418 return OK;
419 }
420
421 status_t status;
422 if (!mDataMQ) {
423 // In case if playback starts close to the end of a compressed track, the bytes
424 // that need to be written is less than the actual buffer size. Need to use
425 // full buffer size for the MQ since otherwise after seeking back to the middle
426 // data will be truncated.
427 size_t bufferSize;
428 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
429 return status;
430 }
431 if (bytes > bufferSize) bufferSize = bytes;
432 if ((status = prepareForWriting(bufferSize)) != OK) {
433 return status;
434 }
435 }
436
437 status = callWriterThread(
438 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
439 [&] (const WriteStatus& writeStatus) {
440 *written = writeStatus.reply.written;
441 // Diagnostics of the cause of b/35813113.
442 ALOGE_IF(*written > bytes,
443 "hal reports more bytes written than asked for: %lld > %lld",
444 (long long)*written, (long long)bytes);
445 });
446 mStreamPowerLog.log(buffer, *written);
447 return status;
448}
449
450status_t StreamOutHalHidl::callWriterThread(
451 WriteCommand cmd, const char* cmdName,
452 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
453 if (!mCommandMQ->write(&cmd)) {
454 ALOGE("command message queue write failed for \"%s\"", cmdName);
455 return -EAGAIN;
456 }
457 if (data != nullptr) {
458 size_t availableToWrite = mDataMQ->availableToWrite();
459 if (dataSize > availableToWrite) {
460 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
461 (long long)dataSize, (long long)availableToWrite);
462 dataSize = availableToWrite;
463 }
464 if (!mDataMQ->write(data, dataSize)) {
465 ALOGE("data message queue write failed for \"%s\"", cmdName);
466 }
467 }
468 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
469
470 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
471 uint32_t efState = 0;
472retry:
473 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
474 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
475 WriteStatus writeStatus;
476 writeStatus.retval = Result::NOT_INITIALIZED;
477 if (!mStatusMQ->read(&writeStatus)) {
478 ALOGE("status message read failed for \"%s\"", cmdName);
479 }
480 if (writeStatus.retval == Result::OK) {
481 ret = OK;
482 callback(writeStatus);
483 } else {
484 ret = processReturn(cmdName, writeStatus.retval);
485 }
486 return ret;
487 }
488 if (ret == -EAGAIN || ret == -EINTR) {
489 // Spurious wakeup. This normally retries no more than once.
490 goto retry;
491 }
492 return ret;
493}
494
495status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
496 std::unique_ptr<CommandMQ> tempCommandMQ;
497 std::unique_ptr<DataMQ> tempDataMQ;
498 std::unique_ptr<StatusMQ> tempStatusMQ;
499 Result retval;
500 pid_t halThreadPid, halThreadTid;
501 Return<void> ret = mStream->prepareForWriting(
502 1, bufferSize,
503 [&](Result r,
504 const CommandMQ::Descriptor& commandMQ,
505 const DataMQ::Descriptor& dataMQ,
506 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganovcc73ef02020-11-06 10:09:52 -0800507 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800508 retval = r;
509 if (retval == Result::OK) {
510 tempCommandMQ.reset(new CommandMQ(commandMQ));
511 tempDataMQ.reset(new DataMQ(dataMQ));
512 tempStatusMQ.reset(new StatusMQ(statusMQ));
513 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
514 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
515 }
Mikhail Naganovcc73ef02020-11-06 10:09:52 -0800516#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800517 halThreadPid = halThreadInfo.pid;
518 halThreadTid = halThreadInfo.tid;
Mikhail Naganovcc73ef02020-11-06 10:09:52 -0800519#else
520 halThreadTid = halThreadInfo;
521#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800522 }
523 });
524 if (!ret.isOk() || retval != Result::OK) {
525 return processReturn("prepareForWriting", ret, retval);
526 }
527 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
528 !tempDataMQ || !tempDataMQ->isValid() ||
529 !tempStatusMQ || !tempStatusMQ->isValid() ||
530 !mEfGroup) {
531 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
532 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
533 "Command message queue for writing is invalid");
534 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
535 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
536 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
537 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
538 "Status message queue for writing is invalid");
539 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
540 return NO_INIT;
541 }
Mikhail Naganovcc73ef02020-11-06 10:09:52 -0800542#if MAJOR_VERSION >= 7
543 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
544 return status;
545 }
546#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800547 requestHalThreadPriority(halThreadPid, halThreadTid);
548
549 mCommandMQ = std::move(tempCommandMQ);
550 mDataMQ = std::move(tempDataMQ);
551 mStatusMQ = std::move(tempStatusMQ);
552 mWriterClient = gettid();
553 return OK;
554}
555
556status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
557 if (mStream == 0) return NO_INIT;
558 Result retval;
559 Return<void> ret = mStream->getRenderPosition(
560 [&](Result r, uint32_t d) {
561 retval = r;
562 if (retval == Result::OK) {
563 *dspFrames = d;
564 }
565 });
566 return processReturn("getRenderPosition", ret, retval);
567}
568
569status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
570 if (mStream == 0) return NO_INIT;
571 Result retval;
572 Return<void> ret = mStream->getNextWriteTimestamp(
573 [&](Result r, int64_t t) {
574 retval = r;
575 if (retval == Result::OK) {
576 *timestamp = t;
577 }
578 });
579 return processReturn("getRenderPosition", ret, retval);
580}
581
582status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
583 if (mStream == 0) return NO_INIT;
584 status_t status = processReturn(
585 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
586 if (status == OK) {
587 mCallback = callback;
588 }
589 return status;
590}
591
592status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
593 if (mStream == 0) return NO_INIT;
594 Return<void> ret = mStream->supportsPauseAndResume(
595 [&](bool p, bool r) {
596 *supportsPause = p;
597 *supportsResume = r;
598 });
599 return processReturn("supportsPauseAndResume", ret);
600}
601
602status_t StreamOutHalHidl::pause() {
603 if (mStream == 0) return NO_INIT;
604 return processReturn("pause", mStream->pause());
605}
606
607status_t StreamOutHalHidl::resume() {
608 if (mStream == 0) return NO_INIT;
609 return processReturn("pause", mStream->resume());
610}
611
612status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
613 if (mStream == 0) return NO_INIT;
614 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
615}
616
617status_t StreamOutHalHidl::drain(bool earlyNotify) {
618 if (mStream == 0) return NO_INIT;
619 return processReturn(
620 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
621}
622
623status_t StreamOutHalHidl::flush() {
624 if (mStream == 0) return NO_INIT;
625 return processReturn("pause", mStream->flush());
626}
627
628status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
629 if (mStream == 0) return NO_INIT;
630 if (mWriterClient == gettid() && mCommandMQ) {
631 return callWriterThread(
632 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
633 [&](const WriteStatus& writeStatus) {
634 *frames = writeStatus.reply.presentationPosition.frames;
635 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
636 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
637 });
638 } else {
639 Result retval;
640 Return<void> ret = mStream->getPresentationPosition(
641 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
642 retval = r;
643 if (retval == Result::OK) {
644 *frames = hidlFrames;
645 timestamp->tv_sec = hidlTimeStamp.tvSec;
646 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
647 }
648 });
649 return processReturn("getPresentationPosition", ret, retval);
650 }
651}
652
Kevin Rocard070e7512018-05-22 09:29:13 -0700653#if MAJOR_VERSION == 2
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800654status_t StreamOutHalHidl::updateSourceMetadata(
655 const StreamOutHalInterface::SourceMetadata& /* sourceMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700656 // Audio HAL V2.0 does not support propagating source metadata
657 return INVALID_OPERATION;
658}
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800659#elif MAJOR_VERSION >= 4
Mikhail Naganov9ccaa162018-12-12 10:27:29 -0800660status_t StreamOutHalHidl::updateSourceMetadata(
661 const StreamOutHalInterface::SourceMetadata& sourceMetadata) {
Mikhail Naganovcc73ef02020-11-06 10:09:52 -0800662 CPP_VERSION::SourceMetadata hidlMetadata;
663 if (status_t status = CoreUtils::sourceMetadataFromHalV7(
664 sourceMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
665 status != OK) {
666 return status;
667 }
668 return processReturn("updateSourceMetadata", mStream->updateSourceMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -0700669}
Kevin Rocard070e7512018-05-22 09:29:13 -0700670#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700671
jiabinf6eb4c32020-02-25 14:06:25 -0800672#if MAJOR_VERSION < 6
Kuowei Li3bea3a42020-08-13 14:44:25 +0800673status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode __unused) {
674 return INVALID_OPERATION;
675}
676
677status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode __unused) {
678 return INVALID_OPERATION;
679}
680
681status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB __unused) {
682 return INVALID_OPERATION;
683}
684
685status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB __unused) {
686 return INVALID_OPERATION;
687}
688
689status_t StreamOutHalHidl::getPlaybackRateParameters(
690 audio_playback_rate_t* playbackRate __unused) {
691 return INVALID_OPERATION;
692}
693
694status_t StreamOutHalHidl::setPlaybackRateParameters(
695 const audio_playback_rate_t& playbackRate __unused) {
696 return INVALID_OPERATION;
697}
698
jiabinf6eb4c32020-02-25 14:06:25 -0800699status_t StreamOutHalHidl::setEventCallback(
700 const sp<StreamOutHalInterfaceEventCallback>& callback __unused) {
701 // Codec format callback is supported starting from audio HAL V6.0
702 return INVALID_OPERATION;
703}
704#else
705
Kuowei Li3bea3a42020-08-13 14:44:25 +0800706status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode) {
707 if (mStream == 0) return NO_INIT;
708 Result retval;
709 Return<void> ret = mStream->getDualMonoMode(
710 [&](Result r, DualMonoMode hidlMode) {
711 retval = r;
712 if (retval == Result::OK) {
713 *mode = static_cast<audio_dual_mono_mode_t>(hidlMode);
714 }
715 });
716 return processReturn("getDualMonoMode", ret, retval);
717}
718
719status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode) {
720 if (mStream == 0) return NO_INIT;
721 return processReturn(
722 "setDualMonoMode", mStream->setDualMonoMode(static_cast<DualMonoMode>(mode)));
723}
724
725status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB) {
726 if (mStream == 0) return NO_INIT;
727 Result retval;
728 Return<void> ret = mStream->getAudioDescriptionMixLevel(
729 [&](Result r, float hidlLeveldB) {
730 retval = r;
731 if (retval == Result::OK) {
732 *leveldB = hidlLeveldB;
733 }
734 });
735 return processReturn("getAudioDescriptionMixLevel", ret, retval);
736}
737
738status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB) {
739 if (mStream == 0) return NO_INIT;
740 return processReturn(
741 "setAudioDescriptionMixLevel", mStream->setAudioDescriptionMixLevel(leveldB));
742}
743
744status_t StreamOutHalHidl::getPlaybackRateParameters(audio_playback_rate_t* playbackRate) {
745 if (mStream == 0) return NO_INIT;
746 Result retval;
747 Return<void> ret = mStream->getPlaybackRateParameters(
748 [&](Result r, PlaybackRate hidlPlaybackRate) {
749 retval = r;
750 if (retval == Result::OK) {
751 playbackRate->mSpeed = hidlPlaybackRate.speed;
752 playbackRate->mPitch = hidlPlaybackRate.pitch;
753 playbackRate->mStretchMode =
754 static_cast<audio_timestretch_stretch_mode_t>(
755 hidlPlaybackRate.timestretchMode);
756 playbackRate->mFallbackMode =
757 static_cast<audio_timestretch_fallback_mode_t>(
758 hidlPlaybackRate.fallbackMode);
759 }
760 });
761 return processReturn("getPlaybackRateParameters", ret, retval);
762}
763
764status_t StreamOutHalHidl::setPlaybackRateParameters(const audio_playback_rate_t& playbackRate) {
765 if (mStream == 0) return NO_INIT;
766 return processReturn(
767 "setPlaybackRateParameters", mStream->setPlaybackRateParameters(
768 PlaybackRate{playbackRate.mSpeed, playbackRate.mPitch,
769 static_cast<TimestretchMode>(playbackRate.mStretchMode),
770 static_cast<TimestretchFallbackMode>(playbackRate.mFallbackMode)}));
771}
772
jiabinf6eb4c32020-02-25 14:06:25 -0800773#include PATH(android/hardware/audio/FILE_VERSION/IStreamOutEventCallback.h)
774
775namespace {
776
777struct StreamOutEventCallback : public IStreamOutEventCallback {
778 StreamOutEventCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
779
780 // IStreamOutEventCallback implementation
781 Return<void> onCodecFormatChanged(
782 const android::hardware::hidl_vec<uint8_t>& audioMetadata) override {
783 sp<StreamOutHalHidl> stream = mStream.promote();
784 if (stream != nullptr) {
785 std::basic_string<uint8_t> metadataBs(audioMetadata.begin(), audioMetadata.end());
786 stream->onCodecFormatChanged(metadataBs);
787 }
788 return Void();
789 }
790
791 private:
792 wp<StreamOutHalHidl> mStream;
793};
794
795} // namespace
796
797status_t StreamOutHalHidl::setEventCallback(
798 const sp<StreamOutHalInterfaceEventCallback>& callback) {
799 if (mStream == nullptr) return NO_INIT;
800 mEventCallback = callback;
801 status_t status = processReturn(
802 "setEventCallback",
803 mStream->setEventCallback(
804 callback.get() == nullptr ? nullptr : new StreamOutEventCallback(this)));
805 return status;
806}
807#endif
808
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800809void StreamOutHalHidl::onWriteReady() {
810 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
811 if (callback == 0) return;
812 ALOGV("asyncCallback onWriteReady");
813 callback->onWriteReady();
814}
815
816void StreamOutHalHidl::onDrainReady() {
817 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
818 if (callback == 0) return;
819 ALOGV("asyncCallback onDrainReady");
820 callback->onDrainReady();
821}
822
823void StreamOutHalHidl::onError() {
824 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
825 if (callback == 0) return;
826 ALOGV("asyncCallback onError");
827 callback->onError();
828}
829
jiabinf6eb4c32020-02-25 14:06:25 -0800830void StreamOutHalHidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) {
831 sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.promote();
832 if (callback == nullptr) return;
833 ALOGV("asyncCodecFormatCallback %s", __func__);
834 callback->onCodecFormatChanged(metadataBs);
835}
836
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800837
838StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
839 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
840}
841
842StreamInHalHidl::~StreamInHalHidl() {
843 if (mStream != 0) {
844 processReturn("close", mStream->close());
845 mStream.clear();
846 hardware::IPCThreadState::self()->flushCommands();
847 }
848 if (mEfGroup) {
849 EventFlag::deleteEventFlag(&mEfGroup);
850 }
851}
852
853status_t StreamInHalHidl::getFrameSize(size_t *size) {
854 if (mStream == 0) return NO_INIT;
855 return processReturn("getFrameSize", mStream->getFrameSize(), size);
856}
857
858status_t StreamInHalHidl::setGain(float gain) {
859 if (mStream == 0) return NO_INIT;
860 return processReturn("setGain", mStream->setGain(gain));
861}
862
863status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
864 if (mStream == 0) return NO_INIT;
865 *read = 0;
866
867 if (bytes == 0 && !mDataMQ) {
868 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
869 return OK;
870 }
871
872 status_t status;
873 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
874 return status;
875 }
876
877 ReadParameters params;
878 params.command = ReadCommand::READ;
879 params.params.read = bytes;
880 status = callReaderThread(params, "read",
881 [&](const ReadStatus& readStatus) {
882 const size_t availToRead = mDataMQ->availableToRead();
883 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
884 ALOGE("data message queue read failed for \"read\"");
885 }
886 ALOGW_IF(availToRead != readStatus.reply.read,
887 "HAL read report inconsistent: mq = %d, status = %d",
888 (int32_t)availToRead, (int32_t)readStatus.reply.read);
889 *read = readStatus.reply.read;
890 });
891 mStreamPowerLog.log(buffer, *read);
892 return status;
893}
894
895status_t StreamInHalHidl::callReaderThread(
896 const ReadParameters& params, const char* cmdName,
897 StreamInHalHidl::ReaderCallback callback) {
898 if (!mCommandMQ->write(&params)) {
899 ALOGW("command message queue write failed");
900 return -EAGAIN;
901 }
902 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
903
904 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
905 uint32_t efState = 0;
906retry:
907 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
908 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
909 ReadStatus readStatus;
910 readStatus.retval = Result::NOT_INITIALIZED;
911 if (!mStatusMQ->read(&readStatus)) {
912 ALOGE("status message read failed for \"%s\"", cmdName);
913 }
914 if (readStatus.retval == Result::OK) {
915 ret = OK;
916 callback(readStatus);
917 } else {
918 ret = processReturn(cmdName, readStatus.retval);
919 }
920 return ret;
921 }
922 if (ret == -EAGAIN || ret == -EINTR) {
923 // Spurious wakeup. This normally retries no more than once.
924 goto retry;
925 }
926 return ret;
927}
928
929status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
930 std::unique_ptr<CommandMQ> tempCommandMQ;
931 std::unique_ptr<DataMQ> tempDataMQ;
932 std::unique_ptr<StatusMQ> tempStatusMQ;
933 Result retval;
934 pid_t halThreadPid, halThreadTid;
935 Return<void> ret = mStream->prepareForReading(
936 1, bufferSize,
937 [&](Result r,
938 const CommandMQ::Descriptor& commandMQ,
939 const DataMQ::Descriptor& dataMQ,
940 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganovcc73ef02020-11-06 10:09:52 -0800941 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800942 retval = r;
943 if (retval == Result::OK) {
944 tempCommandMQ.reset(new CommandMQ(commandMQ));
945 tempDataMQ.reset(new DataMQ(dataMQ));
946 tempStatusMQ.reset(new StatusMQ(statusMQ));
947 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
948 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
949 }
Mikhail Naganovcc73ef02020-11-06 10:09:52 -0800950#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800951 halThreadPid = halThreadInfo.pid;
952 halThreadTid = halThreadInfo.tid;
Mikhail Naganovcc73ef02020-11-06 10:09:52 -0800953#else
954 halThreadTid = halThreadInfo;
955#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800956 }
957 });
958 if (!ret.isOk() || retval != Result::OK) {
959 return processReturn("prepareForReading", ret, retval);
960 }
961 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
962 !tempDataMQ || !tempDataMQ->isValid() ||
963 !tempStatusMQ || !tempStatusMQ->isValid() ||
964 !mEfGroup) {
965 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
966 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
967 "Command message queue for writing is invalid");
968 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
969 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
970 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
971 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
972 "Status message queue for reading is invalid");
973 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
974 return NO_INIT;
975 }
Mikhail Naganovcc73ef02020-11-06 10:09:52 -0800976#if MAJOR_VERSION >= 7
977 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
978 return status;
979 }
980#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800981 requestHalThreadPriority(halThreadPid, halThreadTid);
982
983 mCommandMQ = std::move(tempCommandMQ);
984 mDataMQ = std::move(tempDataMQ);
985 mStatusMQ = std::move(tempStatusMQ);
986 mReaderClient = gettid();
987 return OK;
988}
989
990status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
991 if (mStream == 0) return NO_INIT;
992 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
993}
994
995status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
996 if (mStream == 0) return NO_INIT;
997 if (mReaderClient == gettid() && mCommandMQ) {
998 ReadParameters params;
999 params.command = ReadCommand::GET_CAPTURE_POSITION;
1000 return callReaderThread(params, "getCapturePosition",
1001 [&](const ReadStatus& readStatus) {
1002 *frames = readStatus.reply.capturePosition.frames;
1003 *time = readStatus.reply.capturePosition.time;
1004 });
1005 } else {
1006 Result retval;
1007 Return<void> ret = mStream->getCapturePosition(
1008 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
1009 retval = r;
1010 if (retval == Result::OK) {
1011 *frames = hidlFrames;
1012 *time = hidlTime;
1013 }
1014 });
1015 return processReturn("getCapturePosition", ret, retval);
1016 }
1017}
1018
Kevin Rocard070e7512018-05-22 09:29:13 -07001019#if MAJOR_VERSION == 2
1020status_t StreamInHalHidl::getActiveMicrophones(
1021 std::vector<media::MicrophoneInfo> *microphones __unused) {
1022 if (mStream == 0) return NO_INIT;
1023 return INVALID_OPERATION;
1024}
1025
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001026status_t StreamInHalHidl::updateSinkMetadata(
1027 const StreamInHalInterface::SinkMetadata& /* sinkMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -07001028 // Audio HAL V2.0 does not support propagating sink metadata
1029 return INVALID_OPERATION;
1030}
1031
Kevin Rocard3d48dce2018-11-08 17:16:57 -08001032#elif MAJOR_VERSION >= 4
jiabin9ff780e2018-03-19 18:19:52 -07001033status_t StreamInHalHidl::getActiveMicrophones(
1034 std::vector<media::MicrophoneInfo> *microphonesInfo) {
1035 if (!mStream) return NO_INIT;
1036 Result retval;
1037 Return<void> ret = mStream->getActiveMicrophones(
1038 [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
1039 retval = r;
1040 for (size_t k = 0; k < micArrayHal.size(); k++) {
1041 audio_microphone_characteristic_t dst;
1042 // convert
Mikhail Naganovcc73ef02020-11-06 10:09:52 -08001043 (void)CoreUtils::microphoneInfoToHal(micArrayHal[k], &dst);
jiabin9ff780e2018-03-19 18:19:52 -07001044 media::MicrophoneInfo microphone = media::MicrophoneInfo(dst);
1045 microphonesInfo->push_back(microphone);
1046 }
1047 });
1048 return processReturn("getActiveMicrophones", ret, retval);
1049}
1050
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001051status_t StreamInHalHidl::updateSinkMetadata(const
1052 StreamInHalInterface::SinkMetadata& sinkMetadata) {
Mikhail Naganovcc73ef02020-11-06 10:09:52 -08001053 CPP_VERSION::SinkMetadata hidlMetadata;
1054 if (status_t status = CoreUtils::sinkMetadataFromHalV7(
1055 sinkMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
1056 status != OK) {
1057 return status;
1058 }
1059 return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -07001060}
Kevin Rocard070e7512018-05-22 09:29:13 -07001061#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -07001062
Paul McLean03a6e6a2018-12-04 10:54:13 -07001063#if MAJOR_VERSION < 5
Paul McLean12340082019-03-19 09:35:05 -06001064status_t StreamInHalHidl::setPreferredMicrophoneDirection(
1065 audio_microphone_direction_t direction __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001066 if (mStream == 0) return NO_INIT;
1067 return INVALID_OPERATION;
1068}
1069
Paul McLean12340082019-03-19 09:35:05 -06001070status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001071 if (mStream == 0) return NO_INIT;
1072 return INVALID_OPERATION;
1073}
1074#else
Paul McLean12340082019-03-19 09:35:05 -06001075status_t StreamInHalHidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001076 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001077 return processReturn("setPreferredMicrophoneDirection",
1078 mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction)));
Paul McLean03a6e6a2018-12-04 10:54:13 -07001079}
1080
Paul McLean12340082019-03-19 09:35:05 -06001081status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001082 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001083 return processReturn("setPreferredMicrophoneFieldDimension",
Paul McLean03a6e6a2018-12-04 10:54:13 -07001084 mStream->setMicrophoneFieldDimension(zoom));
1085}
1086#endif
1087
Kevin Rocard070e7512018-05-22 09:29:13 -07001088} // namespace CPP_VERSION
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001089} // namespace android