blob: 2a3e2b6ca13810d0a522967115f0c017f5479a71 [file] [log] [blame]
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "StreamHalHidl"
18//#define LOG_NDEBUG 0
19
Mikhail Naganov247b5f92021-01-15 19:16:12 +000020#include <android/hidl/manager/1.0/IServiceManager.h>
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080021#include <hwbinder/IPCThreadState.h>
Mikhail Naganovac917ac2018-11-28 14:03:52 -080022#include <media/AudioParameter.h>
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080023#include <mediautils/SchedulingPolicyService.h>
24#include <utils/Log.h>
25
Mikhail Naganov247b5f92021-01-15 19:16:12 +000026#include PATH(android/hardware/audio/FILE_VERSION/IStreamOutCallback.h)
27#include <HidlUtils.h>
28#include <util/CoreUtils.h>
29
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080030#include "DeviceHalHidl.h"
31#include "EffectHalHidl.h"
Mikhail Naganov247b5f92021-01-15 19:16:12 +000032#include "ParameterUtils.h"
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080033#include "StreamHalHidl.h"
34
Mikhail Naganov247b5f92021-01-15 19:16:12 +000035using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils;
36using ::android::hardware::audio::CPP_VERSION::implementation::CoreUtils;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080037using ::android::hardware::MQDescriptorSync;
38using ::android::hardware::Return;
39using ::android::hardware::Void;
Kevin Rocarddf9b4202018-05-10 19:56:08 -070040
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080041namespace android {
Kevin Rocard070e7512018-05-22 09:29:13 -070042namespace CPP_VERSION {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080043
Mikhail Naganov595caa32018-12-13 11:08:28 -080044using EffectHalHidl = ::android::effect::CPP_VERSION::EffectHalHidl;
Mikhail Naganov9ccaa162018-12-12 10:27:29 -080045using ReadCommand = ::android::hardware::audio::CPP_VERSION::IStreamIn::ReadCommand;
46
47using namespace ::android::hardware::audio::common::CPP_VERSION;
48using namespace ::android::hardware::audio::CPP_VERSION;
49
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080050StreamHalHidl::StreamHalHidl(IStream *stream)
51 : ConversionHelperHidl("Stream"),
52 mStream(stream),
53 mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT),
54 mCachedBufferSize(0){
55
56 // Instrument audio signal power logging.
57 // Note: This assumes channel mask, format, and sample rate do not change after creation.
Mikhail Naganov247b5f92021-01-15 19:16:12 +000058 audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
59 if (/* mStreamPowerLog.isUserDebugOrEngBuild() && */
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
Andy Hungacb5b982021-01-20 10:12:00 -080066StreamHalHidl::~StreamHalHidl() {
67 // The last step is to flush all binder commands so that the deletion
68 // of IStreamIn / IStreamOut (mStream) is issued with less delay. See b/35394629.
69 hardware::IPCThreadState::self()->flushCommands();
70}
71
Mikhail Naganov247b5f92021-01-15 19:16:12 +000072// Note: this method will be removed
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080073status_t StreamHalHidl::getSampleRate(uint32_t *rate) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +000074 audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
75 status_t status = getAudioProperties(&config.sample_rate, &config.channel_mask, &config.format);
76 *rate = config.sample_rate;
77 return status;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080078}
79
80status_t StreamHalHidl::getBufferSize(size_t *size) {
81 if (!mStream) return NO_INIT;
82 status_t status = processReturn("getBufferSize", mStream->getBufferSize(), size);
83 if (status == OK) {
84 mCachedBufferSize = *size;
85 }
86 return status;
87}
88
Mikhail Naganov247b5f92021-01-15 19:16:12 +000089// Note: this method will be removed
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080090status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +000091 audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
92 status_t status = getAudioProperties(&config.sample_rate, &config.channel_mask, &config.format);
93 *mask = config.channel_mask;
94 return status;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080095}
96
Mikhail Naganov247b5f92021-01-15 19:16:12 +000097// Note: this method will be removed
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080098status_t StreamHalHidl::getFormat(audio_format_t *format) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +000099 audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
100 status_t status = getAudioProperties(&config.sample_rate, &config.channel_mask, &config.format);
101 *format = config.format;
102 return status;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800103}
104
105status_t StreamHalHidl::getAudioProperties(
106 uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) {
107 if (!mStream) return NO_INIT;
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000108#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800109 Return<void> ret = mStream->getAudioProperties(
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800110 [&](uint32_t sr, auto m, auto f) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800111 *sampleRate = sr;
112 *mask = static_cast<audio_channel_mask_t>(m);
113 *format = static_cast<audio_format_t>(f);
114 });
115 return processReturn("getAudioProperties", ret);
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000116#else
117 Result retval;
118 status_t conversionStatus = BAD_VALUE;
119 audio_config_base_t halConfig = AUDIO_CONFIG_BASE_INITIALIZER;
120 Return<void> ret = mStream->getAudioProperties(
121 [&](Result r, const AudioConfigBase& config) {
122 retval = r;
123 if (retval == Result::OK) {
124 conversionStatus = HidlUtils::audioConfigBaseToHal(config, &halConfig);
125 }
126 });
127 if (status_t status = processReturn("getAudioProperties", ret, retval); status == NO_ERROR) {
128 *sampleRate = halConfig.sample_rate;
129 *mask = halConfig.channel_mask;
130 *format = halConfig.format;
131 return conversionStatus;
132 } else {
133 return status;
134 }
135#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800136}
137
138status_t StreamHalHidl::setParameters(const String8& kvPairs) {
139 if (!mStream) return NO_INIT;
140 hidl_vec<ParameterValue> hidlParams;
141 status_t status = parametersFromHal(kvPairs, &hidlParams);
142 if (status != OK) return status;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800143 return processReturn("setParameters",
Dean Wheatley7b417a22019-01-31 20:39:42 +1100144 utils::setParameters(mStream, {} /* context */, hidlParams));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800145}
146
147status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
148 values->clear();
149 if (!mStream) return NO_INIT;
150 hidl_vec<hidl_string> hidlKeys;
151 status_t status = keysFromHal(keys, &hidlKeys);
152 if (status != OK) return status;
153 Result retval;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800154 Return<void> ret = utils::getParameters(
155 mStream,
156 {} /* context */,
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800157 hidlKeys,
158 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
159 retval = r;
160 if (retval == Result::OK) {
161 parametersToHal(parameters, values);
162 }
163 });
164 return processReturn("getParameters", ret, retval);
165}
166
167status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
168 if (!mStream) return NO_INIT;
169 return processReturn("addEffect", mStream->addEffect(
170 static_cast<EffectHalHidl*>(effect.get())->effectId()));
171}
172
173status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
174 if (!mStream) return NO_INIT;
175 return processReturn("removeEffect", mStream->removeEffect(
176 static_cast<EffectHalHidl*>(effect.get())->effectId()));
177}
178
179status_t StreamHalHidl::standby() {
180 if (!mStream) return NO_INIT;
181 return processReturn("standby", mStream->standby());
182}
183
184status_t StreamHalHidl::dump(int fd) {
185 if (!mStream) return NO_INIT;
186 native_handle_t* hidlHandle = native_handle_create(1, 0);
187 hidlHandle->data[0] = fd;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800188 Return<void> ret = mStream->debug(hidlHandle, {} /* options */);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800189 native_handle_delete(hidlHandle);
190 mStreamPowerLog.dump(fd);
191 return processReturn("dump", ret);
192}
193
194status_t StreamHalHidl::start() {
195 if (!mStream) return NO_INIT;
196 return processReturn("start", mStream->start());
197}
198
199status_t StreamHalHidl::stop() {
200 if (!mStream) return NO_INIT;
201 return processReturn("stop", mStream->stop());
202}
203
204status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
205 struct audio_mmap_buffer_info *info) {
206 Result retval;
207 Return<void> ret = mStream->createMmapBuffer(
208 minSizeFrames,
209 [&](Result r, const MmapBufferInfo& hidlInfo) {
210 retval = r;
211 if (retval == Result::OK) {
212 const native_handle *handle = hidlInfo.sharedMemory.handle();
213 if (handle->numFds > 0) {
214 info->shared_memory_fd = handle->data[0];
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800215#if MAJOR_VERSION >= 4
Kevin Rocard734334f2018-07-12 19:37:41 -0700216 info->flags = audio_mmap_buffer_flag(hidlInfo.flags);
217#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800218 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
Kevin Rocard734334f2018-07-12 19:37:41 -0700219 // Negative buffer size frame was a hack in O and P to
220 // indicate that the buffer is shareable to applications
221 if (info->buffer_size_frames < 0) {
222 info->buffer_size_frames *= -1;
223 info->flags = audio_mmap_buffer_flag(
224 info->flags | AUDIO_MMAP_APPLICATION_SHAREABLE);
225 }
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800226 info->burst_size_frames = hidlInfo.burstSizeFrames;
227 // info->shared_memory_address is not needed in HIDL context
228 info->shared_memory_address = NULL;
229 } else {
230 retval = Result::NOT_INITIALIZED;
231 }
232 }
233 });
234 return processReturn("createMmapBuffer", ret, retval);
235}
236
237status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
238 Result retval;
239 Return<void> ret = mStream->getMmapPosition(
240 [&](Result r, const MmapPosition& hidlPosition) {
241 retval = r;
242 if (retval == Result::OK) {
243 position->time_nanoseconds = hidlPosition.timeNanoseconds;
244 position->position_frames = hidlPosition.positionFrames;
245 }
246 });
247 return processReturn("getMmapPosition", ret, retval);
248}
249
250status_t StreamHalHidl::setHalThreadPriority(int priority) {
251 mHalThreadPriority = priority;
252 return OK;
253}
254
255status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
256 if (mCachedBufferSize != 0) {
257 *size = mCachedBufferSize;
258 return OK;
259 }
260 return getBufferSize(size);
261}
262
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000263status_t StreamHalHidl::getHalPid(pid_t *pid) {
264 using ::android::hidl::base::V1_0::DebugInfo;
265 using ::android::hidl::manager::V1_0::IServiceManager;
266
267 DebugInfo debugInfo;
268 auto ret = mStream->getDebugInfo([&] (const auto &info) {
269 debugInfo = info;
270 });
271 if (!ret.isOk()) {
272 return INVALID_OPERATION;
273 }
274 if (debugInfo.pid != (int)IServiceManager::PidConstant::NO_PID) {
275 *pid = debugInfo.pid;
276 return NO_ERROR;
277 }
278 return NAME_NOT_FOUND;
279}
280
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800281bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
282 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
283 return true;
284 }
285 int err = requestPriority(
286 threadPid, threadId,
287 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
288 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
289 mHalThreadPriority, threadPid, threadId, err);
290 // Audio will still work, but latency will be higher and sometimes unacceptable.
291 return err == 0;
292}
293
294namespace {
295
296/* Notes on callback ownership.
297
298This is how (Hw)Binder ownership model looks like. The server implementation
299is owned by Binder framework (via sp<>). Proxies are owned by clients.
300When the last proxy disappears, Binder framework releases the server impl.
301
302Thus, it is not needed to keep any references to StreamOutCallback (this is
303the server impl) -- it will live as long as HAL server holds a strong ref to
304IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
305from the destructor of StreamOutHalHidl.
306
307The callback only keeps a weak reference to the stream. The stream is owned
308by AudioFlinger.
309
310*/
311
312struct StreamOutCallback : public IStreamOutCallback {
313 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
314
315 // IStreamOutCallback implementation
316 Return<void> onWriteReady() override {
317 sp<StreamOutHalHidl> stream = mStream.promote();
318 if (stream != 0) {
319 stream->onWriteReady();
320 }
321 return Void();
322 }
323
324 Return<void> onDrainReady() override {
325 sp<StreamOutHalHidl> stream = mStream.promote();
326 if (stream != 0) {
327 stream->onDrainReady();
328 }
329 return Void();
330 }
331
332 Return<void> onError() override {
333 sp<StreamOutHalHidl> stream = mStream.promote();
334 if (stream != 0) {
335 stream->onError();
336 }
337 return Void();
338 }
339
340 private:
Andy Hung638f45b2021-01-18 20:02:56 -0800341 const wp<StreamOutHalHidl> mStream;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800342};
343
344} // namespace
345
346StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
347 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
348}
349
350StreamOutHalHidl::~StreamOutHalHidl() {
351 if (mStream != 0) {
Andy Hung638f45b2021-01-18 20:02:56 -0800352 if (mCallback.load().unsafe_get()) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800353 processReturn("clearCallback", mStream->clearCallback());
354 }
jiabinf6eb4c32020-02-25 14:06:25 -0800355#if MAJOR_VERSION >= 6
Andy Hung638f45b2021-01-18 20:02:56 -0800356 if (mEventCallback.load().unsafe_get() != nullptr) {
jiabinf6eb4c32020-02-25 14:06:25 -0800357 processReturn("setEventCallback",
358 mStream->setEventCallback(nullptr));
359 }
360#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800361 processReturn("close", mStream->close());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800362 }
Andy Hung638f45b2021-01-18 20:02:56 -0800363 mCallback = nullptr;
364 mEventCallback = nullptr;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800365 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.
Andy Hung638f45b2021-01-18 20:02:56 -0800417 ALOGW_IF(mCallback.load().unsafe_get(), "First call to async write with 0 bytes");
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800418 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 Naganov247b5f92021-01-15 19:16:12 +0000507 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 Naganov247b5f92021-01-15 19:16:12 +0000516#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800517 halThreadPid = halThreadInfo.pid;
518 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000519#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 Naganov247b5f92021-01-15 19:16:12 +0000542#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 Naganov247b5f92021-01-15 19:16:12 +0000662 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 Lid4adbdb2020-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 Lid4adbdb2020-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() {
Andy Hung638f45b2021-01-18 20:02:56 -0800810 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800811 if (callback == 0) return;
812 ALOGV("asyncCallback onWriteReady");
813 callback->onWriteReady();
814}
815
816void StreamOutHalHidl::onDrainReady() {
Andy Hung638f45b2021-01-18 20:02:56 -0800817 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800818 if (callback == 0) return;
819 ALOGV("asyncCallback onDrainReady");
820 callback->onDrainReady();
821}
822
823void StreamOutHalHidl::onError() {
Andy Hung638f45b2021-01-18 20:02:56 -0800824 sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800825 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) {
Andy Hung638f45b2021-01-18 20:02:56 -0800831 sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.load().promote();
jiabinf6eb4c32020-02-25 14:06:25 -0800832 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());
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800845 }
846 if (mEfGroup) {
847 EventFlag::deleteEventFlag(&mEfGroup);
848 }
849}
850
851status_t StreamInHalHidl::getFrameSize(size_t *size) {
852 if (mStream == 0) return NO_INIT;
853 return processReturn("getFrameSize", mStream->getFrameSize(), size);
854}
855
856status_t StreamInHalHidl::setGain(float gain) {
857 if (mStream == 0) return NO_INIT;
858 return processReturn("setGain", mStream->setGain(gain));
859}
860
861status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
862 if (mStream == 0) return NO_INIT;
863 *read = 0;
864
865 if (bytes == 0 && !mDataMQ) {
866 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
867 return OK;
868 }
869
870 status_t status;
871 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
872 return status;
873 }
874
875 ReadParameters params;
876 params.command = ReadCommand::READ;
877 params.params.read = bytes;
878 status = callReaderThread(params, "read",
879 [&](const ReadStatus& readStatus) {
880 const size_t availToRead = mDataMQ->availableToRead();
881 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
882 ALOGE("data message queue read failed for \"read\"");
883 }
884 ALOGW_IF(availToRead != readStatus.reply.read,
885 "HAL read report inconsistent: mq = %d, status = %d",
886 (int32_t)availToRead, (int32_t)readStatus.reply.read);
887 *read = readStatus.reply.read;
888 });
889 mStreamPowerLog.log(buffer, *read);
890 return status;
891}
892
893status_t StreamInHalHidl::callReaderThread(
894 const ReadParameters& params, const char* cmdName,
895 StreamInHalHidl::ReaderCallback callback) {
896 if (!mCommandMQ->write(&params)) {
897 ALOGW("command message queue write failed");
898 return -EAGAIN;
899 }
900 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
901
902 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
903 uint32_t efState = 0;
904retry:
905 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
906 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
907 ReadStatus readStatus;
908 readStatus.retval = Result::NOT_INITIALIZED;
909 if (!mStatusMQ->read(&readStatus)) {
910 ALOGE("status message read failed for \"%s\"", cmdName);
911 }
912 if (readStatus.retval == Result::OK) {
913 ret = OK;
914 callback(readStatus);
915 } else {
916 ret = processReturn(cmdName, readStatus.retval);
917 }
918 return ret;
919 }
920 if (ret == -EAGAIN || ret == -EINTR) {
921 // Spurious wakeup. This normally retries no more than once.
922 goto retry;
923 }
924 return ret;
925}
926
927status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
928 std::unique_ptr<CommandMQ> tempCommandMQ;
929 std::unique_ptr<DataMQ> tempDataMQ;
930 std::unique_ptr<StatusMQ> tempStatusMQ;
931 Result retval;
932 pid_t halThreadPid, halThreadTid;
933 Return<void> ret = mStream->prepareForReading(
934 1, bufferSize,
935 [&](Result r,
936 const CommandMQ::Descriptor& commandMQ,
937 const DataMQ::Descriptor& dataMQ,
938 const StatusMQ::Descriptor& statusMQ,
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000939 const auto& halThreadInfo) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800940 retval = r;
941 if (retval == Result::OK) {
942 tempCommandMQ.reset(new CommandMQ(commandMQ));
943 tempDataMQ.reset(new DataMQ(dataMQ));
944 tempStatusMQ.reset(new StatusMQ(statusMQ));
945 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
946 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
947 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000948#if MAJOR_VERSION <= 6
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800949 halThreadPid = halThreadInfo.pid;
950 halThreadTid = halThreadInfo.tid;
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000951#else
952 halThreadTid = halThreadInfo;
953#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800954 }
955 });
956 if (!ret.isOk() || retval != Result::OK) {
957 return processReturn("prepareForReading", ret, retval);
958 }
959 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
960 !tempDataMQ || !tempDataMQ->isValid() ||
961 !tempStatusMQ || !tempStatusMQ->isValid() ||
962 !mEfGroup) {
963 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
964 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
965 "Command message queue for writing is invalid");
966 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
967 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
968 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
969 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
970 "Status message queue for reading is invalid");
971 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
972 return NO_INIT;
973 }
Mikhail Naganov247b5f92021-01-15 19:16:12 +0000974#if MAJOR_VERSION >= 7
975 if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) {
976 return status;
977 }
978#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800979 requestHalThreadPriority(halThreadPid, halThreadTid);
980
981 mCommandMQ = std::move(tempCommandMQ);
982 mDataMQ = std::move(tempDataMQ);
983 mStatusMQ = std::move(tempStatusMQ);
984 mReaderClient = gettid();
985 return OK;
986}
987
988status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
989 if (mStream == 0) return NO_INIT;
990 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
991}
992
993status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
994 if (mStream == 0) return NO_INIT;
995 if (mReaderClient == gettid() && mCommandMQ) {
996 ReadParameters params;
997 params.command = ReadCommand::GET_CAPTURE_POSITION;
998 return callReaderThread(params, "getCapturePosition",
999 [&](const ReadStatus& readStatus) {
1000 *frames = readStatus.reply.capturePosition.frames;
1001 *time = readStatus.reply.capturePosition.time;
1002 });
1003 } else {
1004 Result retval;
1005 Return<void> ret = mStream->getCapturePosition(
1006 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
1007 retval = r;
1008 if (retval == Result::OK) {
1009 *frames = hidlFrames;
1010 *time = hidlTime;
1011 }
1012 });
1013 return processReturn("getCapturePosition", ret, retval);
1014 }
1015}
1016
Kevin Rocard070e7512018-05-22 09:29:13 -07001017#if MAJOR_VERSION == 2
1018status_t StreamInHalHidl::getActiveMicrophones(
1019 std::vector<media::MicrophoneInfo> *microphones __unused) {
1020 if (mStream == 0) return NO_INIT;
1021 return INVALID_OPERATION;
1022}
1023
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001024status_t StreamInHalHidl::updateSinkMetadata(
1025 const StreamInHalInterface::SinkMetadata& /* sinkMetadata */) {
Kevin Rocard070e7512018-05-22 09:29:13 -07001026 // Audio HAL V2.0 does not support propagating sink metadata
1027 return INVALID_OPERATION;
1028}
1029
Kevin Rocard3d48dce2018-11-08 17:16:57 -08001030#elif MAJOR_VERSION >= 4
jiabin9ff780e2018-03-19 18:19:52 -07001031status_t StreamInHalHidl::getActiveMicrophones(
1032 std::vector<media::MicrophoneInfo> *microphonesInfo) {
1033 if (!mStream) return NO_INIT;
1034 Result retval;
1035 Return<void> ret = mStream->getActiveMicrophones(
1036 [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
1037 retval = r;
1038 for (size_t k = 0; k < micArrayHal.size(); k++) {
1039 audio_microphone_characteristic_t dst;
1040 // convert
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001041 (void)CoreUtils::microphoneInfoToHal(micArrayHal[k], &dst);
jiabin9ff780e2018-03-19 18:19:52 -07001042 media::MicrophoneInfo microphone = media::MicrophoneInfo(dst);
1043 microphonesInfo->push_back(microphone);
1044 }
1045 });
1046 return processReturn("getActiveMicrophones", ret, retval);
1047}
1048
Mikhail Naganov9ccaa162018-12-12 10:27:29 -08001049status_t StreamInHalHidl::updateSinkMetadata(const
1050 StreamInHalInterface::SinkMetadata& sinkMetadata) {
Mikhail Naganov247b5f92021-01-15 19:16:12 +00001051 CPP_VERSION::SinkMetadata hidlMetadata;
1052 if (status_t status = CoreUtils::sinkMetadataFromHalV7(
1053 sinkMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata);
1054 status != OK) {
1055 return status;
1056 }
1057 return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(hidlMetadata));
Kevin Rocarda8975a72018-03-27 10:16:52 -07001058}
Kevin Rocard070e7512018-05-22 09:29:13 -07001059#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -07001060
Paul McLean03a6e6a2018-12-04 10:54:13 -07001061#if MAJOR_VERSION < 5
Paul McLean12340082019-03-19 09:35:05 -06001062status_t StreamInHalHidl::setPreferredMicrophoneDirection(
1063 audio_microphone_direction_t direction __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001064 if (mStream == 0) return NO_INIT;
1065 return INVALID_OPERATION;
1066}
1067
Paul McLean12340082019-03-19 09:35:05 -06001068status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001069 if (mStream == 0) return NO_INIT;
1070 return INVALID_OPERATION;
1071}
1072#else
Paul McLean12340082019-03-19 09:35:05 -06001073status_t StreamInHalHidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001074 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001075 return processReturn("setPreferredMicrophoneDirection",
1076 mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction)));
Paul McLean03a6e6a2018-12-04 10:54:13 -07001077}
1078
Paul McLean12340082019-03-19 09:35:05 -06001079status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom) {
Paul McLean03a6e6a2018-12-04 10:54:13 -07001080 if (!mStream) return NO_INIT;
Paul McLean12340082019-03-19 09:35:05 -06001081 return processReturn("setPreferredMicrophoneFieldDimension",
Paul McLean03a6e6a2018-12-04 10:54:13 -07001082 mStream->setMicrophoneFieldDimension(zoom));
1083}
1084#endif
1085
Kevin Rocard070e7512018-05-22 09:29:13 -07001086} // namespace CPP_VERSION
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001087} // namespace android