blob: bfa80e8c71a9547592f63e11fa2914ea7d2664f6 [file] [log] [blame]
Kevin Rocard4bcd67f2018-02-28 14:33:38 -08001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "StreamHalHidl"
18//#define LOG_NDEBUG 0
19
Kevin Rocard070e7512018-05-22 09:29:13 -070020#include <android/hardware/audio/2.0/IStreamOutCallback.h>
Kevin Rocard51e076a2018-02-28 14:36:53 -080021#include <android/hardware/audio/4.0/IStreamOutCallback.h>
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080022#include <hwbinder/IPCThreadState.h>
23#include <mediautils/SchedulingPolicyService.h>
24#include <utils/Log.h>
25
26#include "DeviceHalHidl.h"
27#include "EffectHalHidl.h"
28#include "StreamHalHidl.h"
Kevin Rocardb9cfbf12018-02-23 19:11:06 -080029#include "VersionUtils.h"
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080030
Kevin Rocard070e7512018-05-22 09:29:13 -070031using ::android::hardware::audio::common::CPP_VERSION::AudioChannelMask;
32using ::android::hardware::audio::common::CPP_VERSION::AudioFormat;
33using ::android::hardware::audio::common::CPP_VERSION::ThreadInfo;
34using ::android::hardware::audio::CPP_VERSION::AudioDrain;
35using ::android::hardware::audio::CPP_VERSION::IStreamOutCallback;
36using ::android::hardware::audio::CPP_VERSION::MessageQueueFlagBits;
37using ::android::hardware::audio::CPP_VERSION::MmapBufferInfo;
38using ::android::hardware::audio::CPP_VERSION::MmapPosition;
39using ::android::hardware::audio::CPP_VERSION::ParameterValue;
40using ::android::hardware::audio::CPP_VERSION::Result;
41using ::android::hardware::audio::CPP_VERSION::TimeSpec;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080042using ::android::hardware::MQDescriptorSync;
43using ::android::hardware::Return;
44using ::android::hardware::Void;
Kevin Rocard070e7512018-05-22 09:29:13 -070045using ReadCommand = ::android::hardware::audio::CPP_VERSION::IStreamIn::ReadCommand;
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080046
Kevin Rocard070e7512018-05-22 09:29:13 -070047#if MAJOR_VERSION == 4
48using ::android::hardware::audio::common::CPP_VERSION::AudioContentType;
49using ::android::hardware::audio::common::CPP_VERSION::AudioSource;
50using ::android::hardware::audio::common::CPP_VERSION::AudioUsage;
51using ::android::hardware::audio::CPP_VERSION::MicrophoneInfo;
52using ::android::hardware::audio::CPP_VERSION::PlaybackTrackMetadata;
53using ::android::hardware::audio::CPP_VERSION::RecordTrackMetadata;
54#endif
Kevin Rocarddf9b4202018-05-10 19:56:08 -070055
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080056namespace android {
Kevin Rocard070e7512018-05-22 09:29:13 -070057namespace CPP_VERSION {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080058
59StreamHalHidl::StreamHalHidl(IStream *stream)
60 : ConversionHelperHidl("Stream"),
61 mStream(stream),
62 mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT),
63 mCachedBufferSize(0){
64
65 // Instrument audio signal power logging.
66 // Note: This assumes channel mask, format, and sample rate do not change after creation.
67 if (mStream != nullptr && mStreamPowerLog.isUserDebugOrEngBuild()) {
68 // Obtain audio properties (see StreamHalHidl::getAudioProperties() below).
69 Return<void> ret = mStream->getAudioProperties(
Kevin Rocardb9cfbf12018-02-23 19:11:06 -080070 [&](auto sr, auto m, auto f) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080071 mStreamPowerLog.init(sr,
72 static_cast<audio_channel_mask_t>(m),
73 static_cast<audio_format_t>(f));
74 });
75 }
76}
77
78StreamHalHidl::~StreamHalHidl() {
79 mStream = nullptr;
80}
81
82status_t StreamHalHidl::getSampleRate(uint32_t *rate) {
83 if (!mStream) return NO_INIT;
84 return processReturn("getSampleRate", mStream->getSampleRate(), rate);
85}
86
87status_t StreamHalHidl::getBufferSize(size_t *size) {
88 if (!mStream) return NO_INIT;
89 status_t status = processReturn("getBufferSize", mStream->getBufferSize(), size);
90 if (status == OK) {
91 mCachedBufferSize = *size;
92 }
93 return status;
94}
95
96status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) {
97 if (!mStream) return NO_INIT;
98 return processReturn("getChannelMask", mStream->getChannelMask(), mask);
99}
100
101status_t StreamHalHidl::getFormat(audio_format_t *format) {
102 if (!mStream) return NO_INIT;
103 return processReturn("getFormat", mStream->getFormat(), format);
104}
105
106status_t StreamHalHidl::getAudioProperties(
107 uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) {
108 if (!mStream) return NO_INIT;
109 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);
116}
117
118status_t StreamHalHidl::setParameters(const String8& kvPairs) {
119 if (!mStream) return NO_INIT;
120 hidl_vec<ParameterValue> hidlParams;
121 status_t status = parametersFromHal(kvPairs, &hidlParams);
122 if (status != OK) return status;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800123 return processReturn("setParameters",
124 utils::setParameters(mStream, hidlParams, {} /* options */));
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800125}
126
127status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
128 values->clear();
129 if (!mStream) return NO_INIT;
130 hidl_vec<hidl_string> hidlKeys;
131 status_t status = keysFromHal(keys, &hidlKeys);
132 if (status != OK) return status;
133 Result retval;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800134 Return<void> ret = utils::getParameters(
135 mStream,
136 {} /* context */,
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800137 hidlKeys,
138 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
139 retval = r;
140 if (retval == Result::OK) {
141 parametersToHal(parameters, values);
142 }
143 });
144 return processReturn("getParameters", ret, retval);
145}
146
147status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
148 if (!mStream) return NO_INIT;
149 return processReturn("addEffect", mStream->addEffect(
150 static_cast<EffectHalHidl*>(effect.get())->effectId()));
151}
152
153status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
154 if (!mStream) return NO_INIT;
155 return processReturn("removeEffect", mStream->removeEffect(
156 static_cast<EffectHalHidl*>(effect.get())->effectId()));
157}
158
159status_t StreamHalHidl::standby() {
160 if (!mStream) return NO_INIT;
161 return processReturn("standby", mStream->standby());
162}
163
164status_t StreamHalHidl::dump(int fd) {
165 if (!mStream) return NO_INIT;
166 native_handle_t* hidlHandle = native_handle_create(1, 0);
167 hidlHandle->data[0] = fd;
Kevin Rocardb9cfbf12018-02-23 19:11:06 -0800168 Return<void> ret = mStream->debug(hidlHandle, {} /* options */);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800169 native_handle_delete(hidlHandle);
170 mStreamPowerLog.dump(fd);
171 return processReturn("dump", ret);
172}
173
174status_t StreamHalHidl::start() {
175 if (!mStream) return NO_INIT;
176 return processReturn("start", mStream->start());
177}
178
179status_t StreamHalHidl::stop() {
180 if (!mStream) return NO_INIT;
181 return processReturn("stop", mStream->stop());
182}
183
184status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
185 struct audio_mmap_buffer_info *info) {
186 Result retval;
187 Return<void> ret = mStream->createMmapBuffer(
188 minSizeFrames,
189 [&](Result r, const MmapBufferInfo& hidlInfo) {
190 retval = r;
191 if (retval == Result::OK) {
192 const native_handle *handle = hidlInfo.sharedMemory.handle();
193 if (handle->numFds > 0) {
194 info->shared_memory_fd = handle->data[0];
Kevin Rocard734334f2018-07-12 19:37:41 -0700195#if MAJOR_VERSION == 4
196 info->flags = audio_mmap_buffer_flag(hidlInfo.flags);
197#endif
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800198 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
Kevin Rocard734334f2018-07-12 19:37:41 -0700199 // Negative buffer size frame was a hack in O and P to
200 // indicate that the buffer is shareable to applications
201 if (info->buffer_size_frames < 0) {
202 info->buffer_size_frames *= -1;
203 info->flags = audio_mmap_buffer_flag(
204 info->flags | AUDIO_MMAP_APPLICATION_SHAREABLE);
205 }
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800206 info->burst_size_frames = hidlInfo.burstSizeFrames;
207 // info->shared_memory_address is not needed in HIDL context
208 info->shared_memory_address = NULL;
209 } else {
210 retval = Result::NOT_INITIALIZED;
211 }
212 }
213 });
214 return processReturn("createMmapBuffer", ret, retval);
215}
216
217status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
218 Result retval;
219 Return<void> ret = mStream->getMmapPosition(
220 [&](Result r, const MmapPosition& hidlPosition) {
221 retval = r;
222 if (retval == Result::OK) {
223 position->time_nanoseconds = hidlPosition.timeNanoseconds;
224 position->position_frames = hidlPosition.positionFrames;
225 }
226 });
227 return processReturn("getMmapPosition", ret, retval);
228}
229
230status_t StreamHalHidl::setHalThreadPriority(int priority) {
231 mHalThreadPriority = priority;
232 return OK;
233}
234
235status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
236 if (mCachedBufferSize != 0) {
237 *size = mCachedBufferSize;
238 return OK;
239 }
240 return getBufferSize(size);
241}
242
243bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
244 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
245 return true;
246 }
247 int err = requestPriority(
248 threadPid, threadId,
249 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
250 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
251 mHalThreadPriority, threadPid, threadId, err);
252 // Audio will still work, but latency will be higher and sometimes unacceptable.
253 return err == 0;
254}
255
256namespace {
257
258/* Notes on callback ownership.
259
260This is how (Hw)Binder ownership model looks like. The server implementation
261is owned by Binder framework (via sp<>). Proxies are owned by clients.
262When the last proxy disappears, Binder framework releases the server impl.
263
264Thus, it is not needed to keep any references to StreamOutCallback (this is
265the server impl) -- it will live as long as HAL server holds a strong ref to
266IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
267from the destructor of StreamOutHalHidl.
268
269The callback only keeps a weak reference to the stream. The stream is owned
270by AudioFlinger.
271
272*/
273
274struct StreamOutCallback : public IStreamOutCallback {
275 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
276
277 // IStreamOutCallback implementation
278 Return<void> onWriteReady() override {
279 sp<StreamOutHalHidl> stream = mStream.promote();
280 if (stream != 0) {
281 stream->onWriteReady();
282 }
283 return Void();
284 }
285
286 Return<void> onDrainReady() override {
287 sp<StreamOutHalHidl> stream = mStream.promote();
288 if (stream != 0) {
289 stream->onDrainReady();
290 }
291 return Void();
292 }
293
294 Return<void> onError() override {
295 sp<StreamOutHalHidl> stream = mStream.promote();
296 if (stream != 0) {
297 stream->onError();
298 }
299 return Void();
300 }
301
302 private:
303 wp<StreamOutHalHidl> mStream;
304};
305
306} // namespace
307
308StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
309 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
310}
311
312StreamOutHalHidl::~StreamOutHalHidl() {
313 if (mStream != 0) {
314 if (mCallback.unsafe_get()) {
315 processReturn("clearCallback", mStream->clearCallback());
316 }
317 processReturn("close", mStream->close());
318 mStream.clear();
319 }
320 mCallback.clear();
321 hardware::IPCThreadState::self()->flushCommands();
322 if (mEfGroup) {
323 EventFlag::deleteEventFlag(&mEfGroup);
324 }
325}
326
327status_t StreamOutHalHidl::getFrameSize(size_t *size) {
328 if (mStream == 0) return NO_INIT;
329 return processReturn("getFrameSize", mStream->getFrameSize(), size);
330}
331
332status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
333 if (mStream == 0) return NO_INIT;
334 if (mWriterClient == gettid() && mCommandMQ) {
335 return callWriterThread(
336 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
337 [&](const WriteStatus& writeStatus) {
338 *latency = writeStatus.reply.latencyMs;
339 });
340 } else {
341 return processReturn("getLatency", mStream->getLatency(), latency);
342 }
343}
344
345status_t StreamOutHalHidl::setVolume(float left, float right) {
346 if (mStream == 0) return NO_INIT;
347 return processReturn("setVolume", mStream->setVolume(left, right));
348}
349
350status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
351 if (mStream == 0) return NO_INIT;
352 *written = 0;
353
354 if (bytes == 0 && !mDataMQ) {
355 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
356 ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes");
357 return OK;
358 }
359
360 status_t status;
361 if (!mDataMQ) {
362 // In case if playback starts close to the end of a compressed track, the bytes
363 // that need to be written is less than the actual buffer size. Need to use
364 // full buffer size for the MQ since otherwise after seeking back to the middle
365 // data will be truncated.
366 size_t bufferSize;
367 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
368 return status;
369 }
370 if (bytes > bufferSize) bufferSize = bytes;
371 if ((status = prepareForWriting(bufferSize)) != OK) {
372 return status;
373 }
374 }
375
376 status = callWriterThread(
377 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
378 [&] (const WriteStatus& writeStatus) {
379 *written = writeStatus.reply.written;
380 // Diagnostics of the cause of b/35813113.
381 ALOGE_IF(*written > bytes,
382 "hal reports more bytes written than asked for: %lld > %lld",
383 (long long)*written, (long long)bytes);
384 });
385 mStreamPowerLog.log(buffer, *written);
386 return status;
387}
388
389status_t StreamOutHalHidl::callWriterThread(
390 WriteCommand cmd, const char* cmdName,
391 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
392 if (!mCommandMQ->write(&cmd)) {
393 ALOGE("command message queue write failed for \"%s\"", cmdName);
394 return -EAGAIN;
395 }
396 if (data != nullptr) {
397 size_t availableToWrite = mDataMQ->availableToWrite();
398 if (dataSize > availableToWrite) {
399 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
400 (long long)dataSize, (long long)availableToWrite);
401 dataSize = availableToWrite;
402 }
403 if (!mDataMQ->write(data, dataSize)) {
404 ALOGE("data message queue write failed for \"%s\"", cmdName);
405 }
406 }
407 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
408
409 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
410 uint32_t efState = 0;
411retry:
412 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
413 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
414 WriteStatus writeStatus;
415 writeStatus.retval = Result::NOT_INITIALIZED;
416 if (!mStatusMQ->read(&writeStatus)) {
417 ALOGE("status message read failed for \"%s\"", cmdName);
418 }
419 if (writeStatus.retval == Result::OK) {
420 ret = OK;
421 callback(writeStatus);
422 } else {
423 ret = processReturn(cmdName, writeStatus.retval);
424 }
425 return ret;
426 }
427 if (ret == -EAGAIN || ret == -EINTR) {
428 // Spurious wakeup. This normally retries no more than once.
429 goto retry;
430 }
431 return ret;
432}
433
434status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
435 std::unique_ptr<CommandMQ> tempCommandMQ;
436 std::unique_ptr<DataMQ> tempDataMQ;
437 std::unique_ptr<StatusMQ> tempStatusMQ;
438 Result retval;
439 pid_t halThreadPid, halThreadTid;
440 Return<void> ret = mStream->prepareForWriting(
441 1, bufferSize,
442 [&](Result r,
443 const CommandMQ::Descriptor& commandMQ,
444 const DataMQ::Descriptor& dataMQ,
445 const StatusMQ::Descriptor& statusMQ,
446 const ThreadInfo& halThreadInfo) {
447 retval = r;
448 if (retval == Result::OK) {
449 tempCommandMQ.reset(new CommandMQ(commandMQ));
450 tempDataMQ.reset(new DataMQ(dataMQ));
451 tempStatusMQ.reset(new StatusMQ(statusMQ));
452 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
453 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
454 }
455 halThreadPid = halThreadInfo.pid;
456 halThreadTid = halThreadInfo.tid;
457 }
458 });
459 if (!ret.isOk() || retval != Result::OK) {
460 return processReturn("prepareForWriting", ret, retval);
461 }
462 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
463 !tempDataMQ || !tempDataMQ->isValid() ||
464 !tempStatusMQ || !tempStatusMQ->isValid() ||
465 !mEfGroup) {
466 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
467 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
468 "Command message queue for writing is invalid");
469 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
470 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
471 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
472 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
473 "Status message queue for writing is invalid");
474 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
475 return NO_INIT;
476 }
477 requestHalThreadPriority(halThreadPid, halThreadTid);
478
479 mCommandMQ = std::move(tempCommandMQ);
480 mDataMQ = std::move(tempDataMQ);
481 mStatusMQ = std::move(tempStatusMQ);
482 mWriterClient = gettid();
483 return OK;
484}
485
486status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
487 if (mStream == 0) return NO_INIT;
488 Result retval;
489 Return<void> ret = mStream->getRenderPosition(
490 [&](Result r, uint32_t d) {
491 retval = r;
492 if (retval == Result::OK) {
493 *dspFrames = d;
494 }
495 });
496 return processReturn("getRenderPosition", ret, retval);
497}
498
499status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
500 if (mStream == 0) return NO_INIT;
501 Result retval;
502 Return<void> ret = mStream->getNextWriteTimestamp(
503 [&](Result r, int64_t t) {
504 retval = r;
505 if (retval == Result::OK) {
506 *timestamp = t;
507 }
508 });
509 return processReturn("getRenderPosition", ret, retval);
510}
511
512status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
513 if (mStream == 0) return NO_INIT;
514 status_t status = processReturn(
515 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
516 if (status == OK) {
517 mCallback = callback;
518 }
519 return status;
520}
521
522status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
523 if (mStream == 0) return NO_INIT;
524 Return<void> ret = mStream->supportsPauseAndResume(
525 [&](bool p, bool r) {
526 *supportsPause = p;
527 *supportsResume = r;
528 });
529 return processReturn("supportsPauseAndResume", ret);
530}
531
532status_t StreamOutHalHidl::pause() {
533 if (mStream == 0) return NO_INIT;
534 return processReturn("pause", mStream->pause());
535}
536
537status_t StreamOutHalHidl::resume() {
538 if (mStream == 0) return NO_INIT;
539 return processReturn("pause", mStream->resume());
540}
541
542status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
543 if (mStream == 0) return NO_INIT;
544 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
545}
546
547status_t StreamOutHalHidl::drain(bool earlyNotify) {
548 if (mStream == 0) return NO_INIT;
549 return processReturn(
550 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
551}
552
553status_t StreamOutHalHidl::flush() {
554 if (mStream == 0) return NO_INIT;
555 return processReturn("pause", mStream->flush());
556}
557
558status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
559 if (mStream == 0) return NO_INIT;
560 if (mWriterClient == gettid() && mCommandMQ) {
561 return callWriterThread(
562 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
563 [&](const WriteStatus& writeStatus) {
564 *frames = writeStatus.reply.presentationPosition.frames;
565 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
566 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
567 });
568 } else {
569 Result retval;
570 Return<void> ret = mStream->getPresentationPosition(
571 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
572 retval = r;
573 if (retval == Result::OK) {
574 *frames = hidlFrames;
575 timestamp->tv_sec = hidlTimeStamp.tvSec;
576 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
577 }
578 });
579 return processReturn("getPresentationPosition", ret, retval);
580 }
581}
582
Kevin Rocard070e7512018-05-22 09:29:13 -0700583#if MAJOR_VERSION == 2
584status_t StreamOutHalHidl::updateSourceMetadata(const SourceMetadata& /* sourceMetadata */) {
585 // Audio HAL V2.0 does not support propagating source metadata
586 return INVALID_OPERATION;
587}
588#elif MAJOR_VERSION == 4
Kevin Rocarda8975a72018-03-27 10:16:52 -0700589/** Transform a standard collection to an HIDL vector. */
590template <class Values, class ElementConverter>
591static auto transformToHidlVec(const Values& values, ElementConverter converter) {
592 hidl_vec<decltype(converter(*values.begin()))> result{values.size()};
593 using namespace std;
594 transform(begin(values), end(values), begin(result), converter);
595 return result;
596}
597
598status_t StreamOutHalHidl::updateSourceMetadata(const SourceMetadata& sourceMetadata) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700599 hardware::audio::CPP_VERSION::SourceMetadata halMetadata = {
Kevin Rocarda8975a72018-03-27 10:16:52 -0700600 .tracks = transformToHidlVec(sourceMetadata.tracks,
601 [](const playback_track_metadata& metadata) -> PlaybackTrackMetadata {
602 return {
603 .usage=static_cast<AudioUsage>(metadata.usage),
604 .contentType=static_cast<AudioContentType>(metadata.content_type),
605 .gain=metadata.gain,
606 };
607 })};
608 return processReturn("updateSourceMetadata", mStream->updateSourceMetadata(halMetadata));
609}
Kevin Rocard070e7512018-05-22 09:29:13 -0700610#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700611
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800612void StreamOutHalHidl::onWriteReady() {
613 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
614 if (callback == 0) return;
615 ALOGV("asyncCallback onWriteReady");
616 callback->onWriteReady();
617}
618
619void StreamOutHalHidl::onDrainReady() {
620 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
621 if (callback == 0) return;
622 ALOGV("asyncCallback onDrainReady");
623 callback->onDrainReady();
624}
625
626void StreamOutHalHidl::onError() {
627 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
628 if (callback == 0) return;
629 ALOGV("asyncCallback onError");
630 callback->onError();
631}
632
633
634StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
635 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
636}
637
638StreamInHalHidl::~StreamInHalHidl() {
639 if (mStream != 0) {
640 processReturn("close", mStream->close());
641 mStream.clear();
642 hardware::IPCThreadState::self()->flushCommands();
643 }
644 if (mEfGroup) {
645 EventFlag::deleteEventFlag(&mEfGroup);
646 }
647}
648
649status_t StreamInHalHidl::getFrameSize(size_t *size) {
650 if (mStream == 0) return NO_INIT;
651 return processReturn("getFrameSize", mStream->getFrameSize(), size);
652}
653
654status_t StreamInHalHidl::setGain(float gain) {
655 if (mStream == 0) return NO_INIT;
656 return processReturn("setGain", mStream->setGain(gain));
657}
658
659status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
660 if (mStream == 0) return NO_INIT;
661 *read = 0;
662
663 if (bytes == 0 && !mDataMQ) {
664 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
665 return OK;
666 }
667
668 status_t status;
669 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
670 return status;
671 }
672
673 ReadParameters params;
674 params.command = ReadCommand::READ;
675 params.params.read = bytes;
676 status = callReaderThread(params, "read",
677 [&](const ReadStatus& readStatus) {
678 const size_t availToRead = mDataMQ->availableToRead();
679 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
680 ALOGE("data message queue read failed for \"read\"");
681 }
682 ALOGW_IF(availToRead != readStatus.reply.read,
683 "HAL read report inconsistent: mq = %d, status = %d",
684 (int32_t)availToRead, (int32_t)readStatus.reply.read);
685 *read = readStatus.reply.read;
686 });
687 mStreamPowerLog.log(buffer, *read);
688 return status;
689}
690
691status_t StreamInHalHidl::callReaderThread(
692 const ReadParameters& params, const char* cmdName,
693 StreamInHalHidl::ReaderCallback callback) {
694 if (!mCommandMQ->write(&params)) {
695 ALOGW("command message queue write failed");
696 return -EAGAIN;
697 }
698 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
699
700 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
701 uint32_t efState = 0;
702retry:
703 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
704 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
705 ReadStatus readStatus;
706 readStatus.retval = Result::NOT_INITIALIZED;
707 if (!mStatusMQ->read(&readStatus)) {
708 ALOGE("status message read failed for \"%s\"", cmdName);
709 }
710 if (readStatus.retval == Result::OK) {
711 ret = OK;
712 callback(readStatus);
713 } else {
714 ret = processReturn(cmdName, readStatus.retval);
715 }
716 return ret;
717 }
718 if (ret == -EAGAIN || ret == -EINTR) {
719 // Spurious wakeup. This normally retries no more than once.
720 goto retry;
721 }
722 return ret;
723}
724
725status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
726 std::unique_ptr<CommandMQ> tempCommandMQ;
727 std::unique_ptr<DataMQ> tempDataMQ;
728 std::unique_ptr<StatusMQ> tempStatusMQ;
729 Result retval;
730 pid_t halThreadPid, halThreadTid;
731 Return<void> ret = mStream->prepareForReading(
732 1, bufferSize,
733 [&](Result r,
734 const CommandMQ::Descriptor& commandMQ,
735 const DataMQ::Descriptor& dataMQ,
736 const StatusMQ::Descriptor& statusMQ,
737 const ThreadInfo& halThreadInfo) {
738 retval = r;
739 if (retval == Result::OK) {
740 tempCommandMQ.reset(new CommandMQ(commandMQ));
741 tempDataMQ.reset(new DataMQ(dataMQ));
742 tempStatusMQ.reset(new StatusMQ(statusMQ));
743 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
744 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
745 }
746 halThreadPid = halThreadInfo.pid;
747 halThreadTid = halThreadInfo.tid;
748 }
749 });
750 if (!ret.isOk() || retval != Result::OK) {
751 return processReturn("prepareForReading", ret, retval);
752 }
753 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
754 !tempDataMQ || !tempDataMQ->isValid() ||
755 !tempStatusMQ || !tempStatusMQ->isValid() ||
756 !mEfGroup) {
757 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
758 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
759 "Command message queue for writing is invalid");
760 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
761 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
762 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
763 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
764 "Status message queue for reading is invalid");
765 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
766 return NO_INIT;
767 }
768 requestHalThreadPriority(halThreadPid, halThreadTid);
769
770 mCommandMQ = std::move(tempCommandMQ);
771 mDataMQ = std::move(tempDataMQ);
772 mStatusMQ = std::move(tempStatusMQ);
773 mReaderClient = gettid();
774 return OK;
775}
776
777status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
778 if (mStream == 0) return NO_INIT;
779 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
780}
781
782status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
783 if (mStream == 0) return NO_INIT;
784 if (mReaderClient == gettid() && mCommandMQ) {
785 ReadParameters params;
786 params.command = ReadCommand::GET_CAPTURE_POSITION;
787 return callReaderThread(params, "getCapturePosition",
788 [&](const ReadStatus& readStatus) {
789 *frames = readStatus.reply.capturePosition.frames;
790 *time = readStatus.reply.capturePosition.time;
791 });
792 } else {
793 Result retval;
794 Return<void> ret = mStream->getCapturePosition(
795 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
796 retval = r;
797 if (retval == Result::OK) {
798 *frames = hidlFrames;
799 *time = hidlTime;
800 }
801 });
802 return processReturn("getCapturePosition", ret, retval);
803 }
804}
805
Kevin Rocard070e7512018-05-22 09:29:13 -0700806#if MAJOR_VERSION == 2
807status_t StreamInHalHidl::getActiveMicrophones(
808 std::vector<media::MicrophoneInfo> *microphones __unused) {
809 if (mStream == 0) return NO_INIT;
810 return INVALID_OPERATION;
811}
812
813status_t StreamInHalHidl::updateSinkMetadata(const SinkMetadata& /* sinkMetadata */) {
814 // Audio HAL V2.0 does not support propagating sink metadata
815 return INVALID_OPERATION;
816}
817
818#elif MAJOR_VERSION == 4
jiabin9ff780e2018-03-19 18:19:52 -0700819status_t StreamInHalHidl::getActiveMicrophones(
820 std::vector<media::MicrophoneInfo> *microphonesInfo) {
821 if (!mStream) return NO_INIT;
822 Result retval;
823 Return<void> ret = mStream->getActiveMicrophones(
824 [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
825 retval = r;
826 for (size_t k = 0; k < micArrayHal.size(); k++) {
827 audio_microphone_characteristic_t dst;
828 // convert
829 microphoneInfoToHal(micArrayHal[k], &dst);
830 media::MicrophoneInfo microphone = media::MicrophoneInfo(dst);
831 microphonesInfo->push_back(microphone);
832 }
833 });
834 return processReturn("getActiveMicrophones", ret, retval);
835}
836
Kevin Rocarda8975a72018-03-27 10:16:52 -0700837status_t StreamInHalHidl::updateSinkMetadata(const SinkMetadata& sinkMetadata) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700838 hardware::audio::CPP_VERSION::SinkMetadata halMetadata = {
Kevin Rocarda8975a72018-03-27 10:16:52 -0700839 .tracks = transformToHidlVec(sinkMetadata.tracks,
840 [](const record_track_metadata& metadata) -> RecordTrackMetadata {
841 return {
842 .source=static_cast<AudioSource>(metadata.source),
843 .gain=metadata.gain,
844 };
845 })};
846 return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(halMetadata));
847}
Kevin Rocard070e7512018-05-22 09:29:13 -0700848#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700849
Kevin Rocard070e7512018-05-22 09:29:13 -0700850} // namespace CPP_VERSION
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800851} // namespace android