blob: b23e01869be7e8fdbfd05fdc5dc00697348de266 [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];
195 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
196 info->burst_size_frames = hidlInfo.burstSizeFrames;
197 // info->shared_memory_address is not needed in HIDL context
198 info->shared_memory_address = NULL;
199 } else {
200 retval = Result::NOT_INITIALIZED;
201 }
202 }
203 });
204 return processReturn("createMmapBuffer", ret, retval);
205}
206
207status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
208 Result retval;
209 Return<void> ret = mStream->getMmapPosition(
210 [&](Result r, const MmapPosition& hidlPosition) {
211 retval = r;
212 if (retval == Result::OK) {
213 position->time_nanoseconds = hidlPosition.timeNanoseconds;
214 position->position_frames = hidlPosition.positionFrames;
215 }
216 });
217 return processReturn("getMmapPosition", ret, retval);
218}
219
220status_t StreamHalHidl::setHalThreadPriority(int priority) {
221 mHalThreadPriority = priority;
222 return OK;
223}
224
225status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
226 if (mCachedBufferSize != 0) {
227 *size = mCachedBufferSize;
228 return OK;
229 }
230 return getBufferSize(size);
231}
232
233bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
234 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
235 return true;
236 }
237 int err = requestPriority(
238 threadPid, threadId,
239 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
240 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
241 mHalThreadPriority, threadPid, threadId, err);
242 // Audio will still work, but latency will be higher and sometimes unacceptable.
243 return err == 0;
244}
245
246namespace {
247
248/* Notes on callback ownership.
249
250This is how (Hw)Binder ownership model looks like. The server implementation
251is owned by Binder framework (via sp<>). Proxies are owned by clients.
252When the last proxy disappears, Binder framework releases the server impl.
253
254Thus, it is not needed to keep any references to StreamOutCallback (this is
255the server impl) -- it will live as long as HAL server holds a strong ref to
256IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
257from the destructor of StreamOutHalHidl.
258
259The callback only keeps a weak reference to the stream. The stream is owned
260by AudioFlinger.
261
262*/
263
264struct StreamOutCallback : public IStreamOutCallback {
265 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
266
267 // IStreamOutCallback implementation
268 Return<void> onWriteReady() override {
269 sp<StreamOutHalHidl> stream = mStream.promote();
270 if (stream != 0) {
271 stream->onWriteReady();
272 }
273 return Void();
274 }
275
276 Return<void> onDrainReady() override {
277 sp<StreamOutHalHidl> stream = mStream.promote();
278 if (stream != 0) {
279 stream->onDrainReady();
280 }
281 return Void();
282 }
283
284 Return<void> onError() override {
285 sp<StreamOutHalHidl> stream = mStream.promote();
286 if (stream != 0) {
287 stream->onError();
288 }
289 return Void();
290 }
291
292 private:
293 wp<StreamOutHalHidl> mStream;
294};
295
296} // namespace
297
298StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
299 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
300}
301
302StreamOutHalHidl::~StreamOutHalHidl() {
303 if (mStream != 0) {
304 if (mCallback.unsafe_get()) {
305 processReturn("clearCallback", mStream->clearCallback());
306 }
307 processReturn("close", mStream->close());
308 mStream.clear();
309 }
310 mCallback.clear();
311 hardware::IPCThreadState::self()->flushCommands();
312 if (mEfGroup) {
313 EventFlag::deleteEventFlag(&mEfGroup);
314 }
315}
316
317status_t StreamOutHalHidl::getFrameSize(size_t *size) {
318 if (mStream == 0) return NO_INIT;
319 return processReturn("getFrameSize", mStream->getFrameSize(), size);
320}
321
322status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
323 if (mStream == 0) return NO_INIT;
324 if (mWriterClient == gettid() && mCommandMQ) {
325 return callWriterThread(
326 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
327 [&](const WriteStatus& writeStatus) {
328 *latency = writeStatus.reply.latencyMs;
329 });
330 } else {
331 return processReturn("getLatency", mStream->getLatency(), latency);
332 }
333}
334
335status_t StreamOutHalHidl::setVolume(float left, float right) {
336 if (mStream == 0) return NO_INIT;
337 return processReturn("setVolume", mStream->setVolume(left, right));
338}
339
340status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
341 if (mStream == 0) return NO_INIT;
342 *written = 0;
343
344 if (bytes == 0 && !mDataMQ) {
345 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
346 ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes");
347 return OK;
348 }
349
350 status_t status;
351 if (!mDataMQ) {
352 // In case if playback starts close to the end of a compressed track, the bytes
353 // that need to be written is less than the actual buffer size. Need to use
354 // full buffer size for the MQ since otherwise after seeking back to the middle
355 // data will be truncated.
356 size_t bufferSize;
357 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
358 return status;
359 }
360 if (bytes > bufferSize) bufferSize = bytes;
361 if ((status = prepareForWriting(bufferSize)) != OK) {
362 return status;
363 }
364 }
365
366 status = callWriterThread(
367 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
368 [&] (const WriteStatus& writeStatus) {
369 *written = writeStatus.reply.written;
370 // Diagnostics of the cause of b/35813113.
371 ALOGE_IF(*written > bytes,
372 "hal reports more bytes written than asked for: %lld > %lld",
373 (long long)*written, (long long)bytes);
374 });
375 mStreamPowerLog.log(buffer, *written);
376 return status;
377}
378
379status_t StreamOutHalHidl::callWriterThread(
380 WriteCommand cmd, const char* cmdName,
381 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
382 if (!mCommandMQ->write(&cmd)) {
383 ALOGE("command message queue write failed for \"%s\"", cmdName);
384 return -EAGAIN;
385 }
386 if (data != nullptr) {
387 size_t availableToWrite = mDataMQ->availableToWrite();
388 if (dataSize > availableToWrite) {
389 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
390 (long long)dataSize, (long long)availableToWrite);
391 dataSize = availableToWrite;
392 }
393 if (!mDataMQ->write(data, dataSize)) {
394 ALOGE("data message queue write failed for \"%s\"", cmdName);
395 }
396 }
397 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
398
399 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
400 uint32_t efState = 0;
401retry:
402 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
403 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
404 WriteStatus writeStatus;
405 writeStatus.retval = Result::NOT_INITIALIZED;
406 if (!mStatusMQ->read(&writeStatus)) {
407 ALOGE("status message read failed for \"%s\"", cmdName);
408 }
409 if (writeStatus.retval == Result::OK) {
410 ret = OK;
411 callback(writeStatus);
412 } else {
413 ret = processReturn(cmdName, writeStatus.retval);
414 }
415 return ret;
416 }
417 if (ret == -EAGAIN || ret == -EINTR) {
418 // Spurious wakeup. This normally retries no more than once.
419 goto retry;
420 }
421 return ret;
422}
423
424status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
425 std::unique_ptr<CommandMQ> tempCommandMQ;
426 std::unique_ptr<DataMQ> tempDataMQ;
427 std::unique_ptr<StatusMQ> tempStatusMQ;
428 Result retval;
429 pid_t halThreadPid, halThreadTid;
430 Return<void> ret = mStream->prepareForWriting(
431 1, bufferSize,
432 [&](Result r,
433 const CommandMQ::Descriptor& commandMQ,
434 const DataMQ::Descriptor& dataMQ,
435 const StatusMQ::Descriptor& statusMQ,
436 const ThreadInfo& halThreadInfo) {
437 retval = r;
438 if (retval == Result::OK) {
439 tempCommandMQ.reset(new CommandMQ(commandMQ));
440 tempDataMQ.reset(new DataMQ(dataMQ));
441 tempStatusMQ.reset(new StatusMQ(statusMQ));
442 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
443 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
444 }
445 halThreadPid = halThreadInfo.pid;
446 halThreadTid = halThreadInfo.tid;
447 }
448 });
449 if (!ret.isOk() || retval != Result::OK) {
450 return processReturn("prepareForWriting", ret, retval);
451 }
452 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
453 !tempDataMQ || !tempDataMQ->isValid() ||
454 !tempStatusMQ || !tempStatusMQ->isValid() ||
455 !mEfGroup) {
456 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
457 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
458 "Command message queue for writing is invalid");
459 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
460 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
461 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
462 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
463 "Status message queue for writing is invalid");
464 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
465 return NO_INIT;
466 }
467 requestHalThreadPriority(halThreadPid, halThreadTid);
468
469 mCommandMQ = std::move(tempCommandMQ);
470 mDataMQ = std::move(tempDataMQ);
471 mStatusMQ = std::move(tempStatusMQ);
472 mWriterClient = gettid();
473 return OK;
474}
475
476status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
477 if (mStream == 0) return NO_INIT;
478 Result retval;
479 Return<void> ret = mStream->getRenderPosition(
480 [&](Result r, uint32_t d) {
481 retval = r;
482 if (retval == Result::OK) {
483 *dspFrames = d;
484 }
485 });
486 return processReturn("getRenderPosition", ret, retval);
487}
488
489status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
490 if (mStream == 0) return NO_INIT;
491 Result retval;
492 Return<void> ret = mStream->getNextWriteTimestamp(
493 [&](Result r, int64_t t) {
494 retval = r;
495 if (retval == Result::OK) {
496 *timestamp = t;
497 }
498 });
499 return processReturn("getRenderPosition", ret, retval);
500}
501
502status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
503 if (mStream == 0) return NO_INIT;
504 status_t status = processReturn(
505 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
506 if (status == OK) {
507 mCallback = callback;
508 }
509 return status;
510}
511
512status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
513 if (mStream == 0) return NO_INIT;
514 Return<void> ret = mStream->supportsPauseAndResume(
515 [&](bool p, bool r) {
516 *supportsPause = p;
517 *supportsResume = r;
518 });
519 return processReturn("supportsPauseAndResume", ret);
520}
521
522status_t StreamOutHalHidl::pause() {
523 if (mStream == 0) return NO_INIT;
524 return processReturn("pause", mStream->pause());
525}
526
527status_t StreamOutHalHidl::resume() {
528 if (mStream == 0) return NO_INIT;
529 return processReturn("pause", mStream->resume());
530}
531
532status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
533 if (mStream == 0) return NO_INIT;
534 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
535}
536
537status_t StreamOutHalHidl::drain(bool earlyNotify) {
538 if (mStream == 0) return NO_INIT;
539 return processReturn(
540 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
541}
542
543status_t StreamOutHalHidl::flush() {
544 if (mStream == 0) return NO_INIT;
545 return processReturn("pause", mStream->flush());
546}
547
548status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
549 if (mStream == 0) return NO_INIT;
550 if (mWriterClient == gettid() && mCommandMQ) {
551 return callWriterThread(
552 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
553 [&](const WriteStatus& writeStatus) {
554 *frames = writeStatus.reply.presentationPosition.frames;
555 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
556 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
557 });
558 } else {
559 Result retval;
560 Return<void> ret = mStream->getPresentationPosition(
561 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
562 retval = r;
563 if (retval == Result::OK) {
564 *frames = hidlFrames;
565 timestamp->tv_sec = hidlTimeStamp.tvSec;
566 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
567 }
568 });
569 return processReturn("getPresentationPosition", ret, retval);
570 }
571}
572
Kevin Rocard070e7512018-05-22 09:29:13 -0700573#if MAJOR_VERSION == 2
574status_t StreamOutHalHidl::updateSourceMetadata(const SourceMetadata& /* sourceMetadata */) {
575 // Audio HAL V2.0 does not support propagating source metadata
576 return INVALID_OPERATION;
577}
578#elif MAJOR_VERSION == 4
Kevin Rocarda8975a72018-03-27 10:16:52 -0700579/** Transform a standard collection to an HIDL vector. */
580template <class Values, class ElementConverter>
581static auto transformToHidlVec(const Values& values, ElementConverter converter) {
582 hidl_vec<decltype(converter(*values.begin()))> result{values.size()};
583 using namespace std;
584 transform(begin(values), end(values), begin(result), converter);
585 return result;
586}
587
588status_t StreamOutHalHidl::updateSourceMetadata(const SourceMetadata& sourceMetadata) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700589 hardware::audio::CPP_VERSION::SourceMetadata halMetadata = {
Kevin Rocarda8975a72018-03-27 10:16:52 -0700590 .tracks = transformToHidlVec(sourceMetadata.tracks,
591 [](const playback_track_metadata& metadata) -> PlaybackTrackMetadata {
592 return {
593 .usage=static_cast<AudioUsage>(metadata.usage),
594 .contentType=static_cast<AudioContentType>(metadata.content_type),
595 .gain=metadata.gain,
596 };
597 })};
598 return processReturn("updateSourceMetadata", mStream->updateSourceMetadata(halMetadata));
599}
Kevin Rocard070e7512018-05-22 09:29:13 -0700600#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700601
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800602void StreamOutHalHidl::onWriteReady() {
603 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
604 if (callback == 0) return;
605 ALOGV("asyncCallback onWriteReady");
606 callback->onWriteReady();
607}
608
609void StreamOutHalHidl::onDrainReady() {
610 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
611 if (callback == 0) return;
612 ALOGV("asyncCallback onDrainReady");
613 callback->onDrainReady();
614}
615
616void StreamOutHalHidl::onError() {
617 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
618 if (callback == 0) return;
619 ALOGV("asyncCallback onError");
620 callback->onError();
621}
622
623
624StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
625 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
626}
627
628StreamInHalHidl::~StreamInHalHidl() {
629 if (mStream != 0) {
630 processReturn("close", mStream->close());
631 mStream.clear();
632 hardware::IPCThreadState::self()->flushCommands();
633 }
634 if (mEfGroup) {
635 EventFlag::deleteEventFlag(&mEfGroup);
636 }
637}
638
639status_t StreamInHalHidl::getFrameSize(size_t *size) {
640 if (mStream == 0) return NO_INIT;
641 return processReturn("getFrameSize", mStream->getFrameSize(), size);
642}
643
644status_t StreamInHalHidl::setGain(float gain) {
645 if (mStream == 0) return NO_INIT;
646 return processReturn("setGain", mStream->setGain(gain));
647}
648
649status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
650 if (mStream == 0) return NO_INIT;
651 *read = 0;
652
653 if (bytes == 0 && !mDataMQ) {
654 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
655 return OK;
656 }
657
658 status_t status;
659 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
660 return status;
661 }
662
663 ReadParameters params;
664 params.command = ReadCommand::READ;
665 params.params.read = bytes;
666 status = callReaderThread(params, "read",
667 [&](const ReadStatus& readStatus) {
668 const size_t availToRead = mDataMQ->availableToRead();
669 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
670 ALOGE("data message queue read failed for \"read\"");
671 }
672 ALOGW_IF(availToRead != readStatus.reply.read,
673 "HAL read report inconsistent: mq = %d, status = %d",
674 (int32_t)availToRead, (int32_t)readStatus.reply.read);
675 *read = readStatus.reply.read;
676 });
677 mStreamPowerLog.log(buffer, *read);
678 return status;
679}
680
681status_t StreamInHalHidl::callReaderThread(
682 const ReadParameters& params, const char* cmdName,
683 StreamInHalHidl::ReaderCallback callback) {
684 if (!mCommandMQ->write(&params)) {
685 ALOGW("command message queue write failed");
686 return -EAGAIN;
687 }
688 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
689
690 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
691 uint32_t efState = 0;
692retry:
693 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
694 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
695 ReadStatus readStatus;
696 readStatus.retval = Result::NOT_INITIALIZED;
697 if (!mStatusMQ->read(&readStatus)) {
698 ALOGE("status message read failed for \"%s\"", cmdName);
699 }
700 if (readStatus.retval == Result::OK) {
701 ret = OK;
702 callback(readStatus);
703 } else {
704 ret = processReturn(cmdName, readStatus.retval);
705 }
706 return ret;
707 }
708 if (ret == -EAGAIN || ret == -EINTR) {
709 // Spurious wakeup. This normally retries no more than once.
710 goto retry;
711 }
712 return ret;
713}
714
715status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
716 std::unique_ptr<CommandMQ> tempCommandMQ;
717 std::unique_ptr<DataMQ> tempDataMQ;
718 std::unique_ptr<StatusMQ> tempStatusMQ;
719 Result retval;
720 pid_t halThreadPid, halThreadTid;
721 Return<void> ret = mStream->prepareForReading(
722 1, bufferSize,
723 [&](Result r,
724 const CommandMQ::Descriptor& commandMQ,
725 const DataMQ::Descriptor& dataMQ,
726 const StatusMQ::Descriptor& statusMQ,
727 const ThreadInfo& halThreadInfo) {
728 retval = r;
729 if (retval == Result::OK) {
730 tempCommandMQ.reset(new CommandMQ(commandMQ));
731 tempDataMQ.reset(new DataMQ(dataMQ));
732 tempStatusMQ.reset(new StatusMQ(statusMQ));
733 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
734 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
735 }
736 halThreadPid = halThreadInfo.pid;
737 halThreadTid = halThreadInfo.tid;
738 }
739 });
740 if (!ret.isOk() || retval != Result::OK) {
741 return processReturn("prepareForReading", ret, retval);
742 }
743 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
744 !tempDataMQ || !tempDataMQ->isValid() ||
745 !tempStatusMQ || !tempStatusMQ->isValid() ||
746 !mEfGroup) {
747 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
748 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
749 "Command message queue for writing is invalid");
750 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
751 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
752 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
753 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
754 "Status message queue for reading is invalid");
755 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
756 return NO_INIT;
757 }
758 requestHalThreadPriority(halThreadPid, halThreadTid);
759
760 mCommandMQ = std::move(tempCommandMQ);
761 mDataMQ = std::move(tempDataMQ);
762 mStatusMQ = std::move(tempStatusMQ);
763 mReaderClient = gettid();
764 return OK;
765}
766
767status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
768 if (mStream == 0) return NO_INIT;
769 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
770}
771
772status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
773 if (mStream == 0) return NO_INIT;
774 if (mReaderClient == gettid() && mCommandMQ) {
775 ReadParameters params;
776 params.command = ReadCommand::GET_CAPTURE_POSITION;
777 return callReaderThread(params, "getCapturePosition",
778 [&](const ReadStatus& readStatus) {
779 *frames = readStatus.reply.capturePosition.frames;
780 *time = readStatus.reply.capturePosition.time;
781 });
782 } else {
783 Result retval;
784 Return<void> ret = mStream->getCapturePosition(
785 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
786 retval = r;
787 if (retval == Result::OK) {
788 *frames = hidlFrames;
789 *time = hidlTime;
790 }
791 });
792 return processReturn("getCapturePosition", ret, retval);
793 }
794}
795
Kevin Rocard070e7512018-05-22 09:29:13 -0700796#if MAJOR_VERSION == 2
797status_t StreamInHalHidl::getActiveMicrophones(
798 std::vector<media::MicrophoneInfo> *microphones __unused) {
799 if (mStream == 0) return NO_INIT;
800 return INVALID_OPERATION;
801}
802
803status_t StreamInHalHidl::updateSinkMetadata(const SinkMetadata& /* sinkMetadata */) {
804 // Audio HAL V2.0 does not support propagating sink metadata
805 return INVALID_OPERATION;
806}
807
808#elif MAJOR_VERSION == 4
jiabin9ff780e2018-03-19 18:19:52 -0700809status_t StreamInHalHidl::getActiveMicrophones(
810 std::vector<media::MicrophoneInfo> *microphonesInfo) {
811 if (!mStream) return NO_INIT;
812 Result retval;
813 Return<void> ret = mStream->getActiveMicrophones(
814 [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) {
815 retval = r;
816 for (size_t k = 0; k < micArrayHal.size(); k++) {
817 audio_microphone_characteristic_t dst;
818 // convert
819 microphoneInfoToHal(micArrayHal[k], &dst);
820 media::MicrophoneInfo microphone = media::MicrophoneInfo(dst);
821 microphonesInfo->push_back(microphone);
822 }
823 });
824 return processReturn("getActiveMicrophones", ret, retval);
825}
826
Kevin Rocarda8975a72018-03-27 10:16:52 -0700827status_t StreamInHalHidl::updateSinkMetadata(const SinkMetadata& sinkMetadata) {
Kevin Rocard070e7512018-05-22 09:29:13 -0700828 hardware::audio::CPP_VERSION::SinkMetadata halMetadata = {
Kevin Rocarda8975a72018-03-27 10:16:52 -0700829 .tracks = transformToHidlVec(sinkMetadata.tracks,
830 [](const record_track_metadata& metadata) -> RecordTrackMetadata {
831 return {
832 .source=static_cast<AudioSource>(metadata.source),
833 .gain=metadata.gain,
834 };
835 })};
836 return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(halMetadata));
837}
Kevin Rocard070e7512018-05-22 09:29:13 -0700838#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700839
Kevin Rocard070e7512018-05-22 09:29:13 -0700840} // namespace CPP_VERSION
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800841} // namespace android