blob: de16e9812550b9ef450301f619f4e14adea8e37f [file] [log] [blame]
Kevin Rocardd4de2882018-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 Rocard2390b5d2018-02-28 14:36:53 -080020#include <android/hardware/audio/4.0/IStreamOutCallback.h>
Kevin Rocardd4de2882018-02-28 14:33:38 -080021#include <hwbinder/IPCThreadState.h>
22#include <mediautils/SchedulingPolicyService.h>
23#include <utils/Log.h>
24
25#include "DeviceHalHidl.h"
26#include "EffectHalHidl.h"
27#include "StreamHalHidl.h"
Kevin Rocard4a7484bd2018-02-23 19:11:06 -080028#include "VersionUtils.h"
Kevin Rocardd4de2882018-02-28 14:33:38 -080029
Kevin Rocard2390b5d2018-02-28 14:36:53 -080030using ::android::hardware::audio::common::V4_0::AudioChannelMask;
31using ::android::hardware::audio::common::V4_0::AudioFormat;
32using ::android::hardware::audio::common::V4_0::ThreadInfo;
33using ::android::hardware::audio::V4_0::AudioDrain;
34using ::android::hardware::audio::V4_0::IStreamOutCallback;
35using ::android::hardware::audio::V4_0::MessageQueueFlagBits;
36using ::android::hardware::audio::V4_0::MmapBufferInfo;
37using ::android::hardware::audio::V4_0::MmapPosition;
38using ::android::hardware::audio::V4_0::ParameterValue;
39using ::android::hardware::audio::V4_0::Result;
40using ::android::hardware::audio::V4_0::TimeSpec;
Kevin Rocardd4de2882018-02-28 14:33:38 -080041using ::android::hardware::MQDescriptorSync;
42using ::android::hardware::Return;
43using ::android::hardware::Void;
Kevin Rocard2390b5d2018-02-28 14:36:53 -080044using ReadCommand = ::android::hardware::audio::V4_0::IStreamIn::ReadCommand;
Kevin Rocardd4de2882018-02-28 14:33:38 -080045
46namespace android {
Kevin Rocard2390b5d2018-02-28 14:36:53 -080047namespace V4_0 {
Kevin Rocardd4de2882018-02-28 14:33:38 -080048
49StreamHalHidl::StreamHalHidl(IStream *stream)
50 : ConversionHelperHidl("Stream"),
51 mStream(stream),
52 mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT),
53 mCachedBufferSize(0){
54
55 // Instrument audio signal power logging.
56 // Note: This assumes channel mask, format, and sample rate do not change after creation.
57 if (mStream != nullptr && mStreamPowerLog.isUserDebugOrEngBuild()) {
58 // Obtain audio properties (see StreamHalHidl::getAudioProperties() below).
59 Return<void> ret = mStream->getAudioProperties(
Kevin Rocard4a7484bd2018-02-23 19:11:06 -080060 [&](auto sr, auto m, auto f) {
Kevin Rocardd4de2882018-02-28 14:33:38 -080061 mStreamPowerLog.init(sr,
62 static_cast<audio_channel_mask_t>(m),
63 static_cast<audio_format_t>(f));
64 });
65 }
66}
67
68StreamHalHidl::~StreamHalHidl() {
69 mStream = nullptr;
70}
71
72status_t StreamHalHidl::getSampleRate(uint32_t *rate) {
73 if (!mStream) return NO_INIT;
74 return processReturn("getSampleRate", mStream->getSampleRate(), rate);
75}
76
77status_t StreamHalHidl::getBufferSize(size_t *size) {
78 if (!mStream) return NO_INIT;
79 status_t status = processReturn("getBufferSize", mStream->getBufferSize(), size);
80 if (status == OK) {
81 mCachedBufferSize = *size;
82 }
83 return status;
84}
85
86status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) {
87 if (!mStream) return NO_INIT;
88 return processReturn("getChannelMask", mStream->getChannelMask(), mask);
89}
90
91status_t StreamHalHidl::getFormat(audio_format_t *format) {
92 if (!mStream) return NO_INIT;
93 return processReturn("getFormat", mStream->getFormat(), format);
94}
95
96status_t StreamHalHidl::getAudioProperties(
97 uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) {
98 if (!mStream) return NO_INIT;
99 Return<void> ret = mStream->getAudioProperties(
Kevin Rocard4a7484bd2018-02-23 19:11:06 -0800100 [&](uint32_t sr, auto m, auto f) {
Kevin Rocardd4de2882018-02-28 14:33:38 -0800101 *sampleRate = sr;
102 *mask = static_cast<audio_channel_mask_t>(m);
103 *format = static_cast<audio_format_t>(f);
104 });
105 return processReturn("getAudioProperties", ret);
106}
107
108status_t StreamHalHidl::setParameters(const String8& kvPairs) {
109 if (!mStream) return NO_INIT;
110 hidl_vec<ParameterValue> hidlParams;
111 status_t status = parametersFromHal(kvPairs, &hidlParams);
112 if (status != OK) return status;
Kevin Rocard4a7484bd2018-02-23 19:11:06 -0800113 return processReturn("setParameters",
114 utils::setParameters(mStream, hidlParams, {} /* options */));
Kevin Rocardd4de2882018-02-28 14:33:38 -0800115}
116
117status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
118 values->clear();
119 if (!mStream) return NO_INIT;
120 hidl_vec<hidl_string> hidlKeys;
121 status_t status = keysFromHal(keys, &hidlKeys);
122 if (status != OK) return status;
123 Result retval;
Kevin Rocard4a7484bd2018-02-23 19:11:06 -0800124 Return<void> ret = utils::getParameters(
125 mStream,
126 {} /* context */,
Kevin Rocardd4de2882018-02-28 14:33:38 -0800127 hidlKeys,
128 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
129 retval = r;
130 if (retval == Result::OK) {
131 parametersToHal(parameters, values);
132 }
133 });
134 return processReturn("getParameters", ret, retval);
135}
136
137status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
138 if (!mStream) return NO_INIT;
139 return processReturn("addEffect", mStream->addEffect(
140 static_cast<EffectHalHidl*>(effect.get())->effectId()));
141}
142
143status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
144 if (!mStream) return NO_INIT;
145 return processReturn("removeEffect", mStream->removeEffect(
146 static_cast<EffectHalHidl*>(effect.get())->effectId()));
147}
148
149status_t StreamHalHidl::standby() {
150 if (!mStream) return NO_INIT;
151 return processReturn("standby", mStream->standby());
152}
153
154status_t StreamHalHidl::dump(int fd) {
155 if (!mStream) return NO_INIT;
156 native_handle_t* hidlHandle = native_handle_create(1, 0);
157 hidlHandle->data[0] = fd;
Kevin Rocard4a7484bd2018-02-23 19:11:06 -0800158 Return<void> ret = mStream->debug(hidlHandle, {} /* options */);
Kevin Rocardd4de2882018-02-28 14:33:38 -0800159 native_handle_delete(hidlHandle);
160 mStreamPowerLog.dump(fd);
161 return processReturn("dump", ret);
162}
163
164status_t StreamHalHidl::start() {
165 if (!mStream) return NO_INIT;
166 return processReturn("start", mStream->start());
167}
168
169status_t StreamHalHidl::stop() {
170 if (!mStream) return NO_INIT;
171 return processReturn("stop", mStream->stop());
172}
173
174status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
175 struct audio_mmap_buffer_info *info) {
176 Result retval;
177 Return<void> ret = mStream->createMmapBuffer(
178 minSizeFrames,
179 [&](Result r, const MmapBufferInfo& hidlInfo) {
180 retval = r;
181 if (retval == Result::OK) {
182 const native_handle *handle = hidlInfo.sharedMemory.handle();
183 if (handle->numFds > 0) {
184 info->shared_memory_fd = handle->data[0];
185 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
186 info->burst_size_frames = hidlInfo.burstSizeFrames;
187 // info->shared_memory_address is not needed in HIDL context
188 info->shared_memory_address = NULL;
189 } else {
190 retval = Result::NOT_INITIALIZED;
191 }
192 }
193 });
194 return processReturn("createMmapBuffer", ret, retval);
195}
196
197status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
198 Result retval;
199 Return<void> ret = mStream->getMmapPosition(
200 [&](Result r, const MmapPosition& hidlPosition) {
201 retval = r;
202 if (retval == Result::OK) {
203 position->time_nanoseconds = hidlPosition.timeNanoseconds;
204 position->position_frames = hidlPosition.positionFrames;
205 }
206 });
207 return processReturn("getMmapPosition", ret, retval);
208}
209
210status_t StreamHalHidl::setHalThreadPriority(int priority) {
211 mHalThreadPriority = priority;
212 return OK;
213}
214
215status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
216 if (mCachedBufferSize != 0) {
217 *size = mCachedBufferSize;
218 return OK;
219 }
220 return getBufferSize(size);
221}
222
223bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
224 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
225 return true;
226 }
227 int err = requestPriority(
228 threadPid, threadId,
229 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
230 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
231 mHalThreadPriority, threadPid, threadId, err);
232 // Audio will still work, but latency will be higher and sometimes unacceptable.
233 return err == 0;
234}
235
236namespace {
237
238/* Notes on callback ownership.
239
240This is how (Hw)Binder ownership model looks like. The server implementation
241is owned by Binder framework (via sp<>). Proxies are owned by clients.
242When the last proxy disappears, Binder framework releases the server impl.
243
244Thus, it is not needed to keep any references to StreamOutCallback (this is
245the server impl) -- it will live as long as HAL server holds a strong ref to
246IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
247from the destructor of StreamOutHalHidl.
248
249The callback only keeps a weak reference to the stream. The stream is owned
250by AudioFlinger.
251
252*/
253
254struct StreamOutCallback : public IStreamOutCallback {
255 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
256
257 // IStreamOutCallback implementation
258 Return<void> onWriteReady() override {
259 sp<StreamOutHalHidl> stream = mStream.promote();
260 if (stream != 0) {
261 stream->onWriteReady();
262 }
263 return Void();
264 }
265
266 Return<void> onDrainReady() override {
267 sp<StreamOutHalHidl> stream = mStream.promote();
268 if (stream != 0) {
269 stream->onDrainReady();
270 }
271 return Void();
272 }
273
274 Return<void> onError() override {
275 sp<StreamOutHalHidl> stream = mStream.promote();
276 if (stream != 0) {
277 stream->onError();
278 }
279 return Void();
280 }
281
282 private:
283 wp<StreamOutHalHidl> mStream;
284};
285
286} // namespace
287
288StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
289 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
290}
291
292StreamOutHalHidl::~StreamOutHalHidl() {
293 if (mStream != 0) {
294 if (mCallback.unsafe_get()) {
295 processReturn("clearCallback", mStream->clearCallback());
296 }
297 processReturn("close", mStream->close());
298 mStream.clear();
299 }
300 mCallback.clear();
301 hardware::IPCThreadState::self()->flushCommands();
302 if (mEfGroup) {
303 EventFlag::deleteEventFlag(&mEfGroup);
304 }
305}
306
307status_t StreamOutHalHidl::getFrameSize(size_t *size) {
308 if (mStream == 0) return NO_INIT;
309 return processReturn("getFrameSize", mStream->getFrameSize(), size);
310}
311
312status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
313 if (mStream == 0) return NO_INIT;
314 if (mWriterClient == gettid() && mCommandMQ) {
315 return callWriterThread(
316 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
317 [&](const WriteStatus& writeStatus) {
318 *latency = writeStatus.reply.latencyMs;
319 });
320 } else {
321 return processReturn("getLatency", mStream->getLatency(), latency);
322 }
323}
324
325status_t StreamOutHalHidl::setVolume(float left, float right) {
326 if (mStream == 0) return NO_INIT;
327 return processReturn("setVolume", mStream->setVolume(left, right));
328}
329
330status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
331 if (mStream == 0) return NO_INIT;
332 *written = 0;
333
334 if (bytes == 0 && !mDataMQ) {
335 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
336 ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes");
337 return OK;
338 }
339
340 status_t status;
341 if (!mDataMQ) {
342 // In case if playback starts close to the end of a compressed track, the bytes
343 // that need to be written is less than the actual buffer size. Need to use
344 // full buffer size for the MQ since otherwise after seeking back to the middle
345 // data will be truncated.
346 size_t bufferSize;
347 if ((status = getCachedBufferSize(&bufferSize)) != OK) {
348 return status;
349 }
350 if (bytes > bufferSize) bufferSize = bytes;
351 if ((status = prepareForWriting(bufferSize)) != OK) {
352 return status;
353 }
354 }
355
356 status = callWriterThread(
357 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
358 [&] (const WriteStatus& writeStatus) {
359 *written = writeStatus.reply.written;
360 // Diagnostics of the cause of b/35813113.
361 ALOGE_IF(*written > bytes,
362 "hal reports more bytes written than asked for: %lld > %lld",
363 (long long)*written, (long long)bytes);
364 });
365 mStreamPowerLog.log(buffer, *written);
366 return status;
367}
368
369status_t StreamOutHalHidl::callWriterThread(
370 WriteCommand cmd, const char* cmdName,
371 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
372 if (!mCommandMQ->write(&cmd)) {
373 ALOGE("command message queue write failed for \"%s\"", cmdName);
374 return -EAGAIN;
375 }
376 if (data != nullptr) {
377 size_t availableToWrite = mDataMQ->availableToWrite();
378 if (dataSize > availableToWrite) {
379 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
380 (long long)dataSize, (long long)availableToWrite);
381 dataSize = availableToWrite;
382 }
383 if (!mDataMQ->write(data, dataSize)) {
384 ALOGE("data message queue write failed for \"%s\"", cmdName);
385 }
386 }
387 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
388
389 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
390 uint32_t efState = 0;
391retry:
392 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
393 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
394 WriteStatus writeStatus;
395 writeStatus.retval = Result::NOT_INITIALIZED;
396 if (!mStatusMQ->read(&writeStatus)) {
397 ALOGE("status message read failed for \"%s\"", cmdName);
398 }
399 if (writeStatus.retval == Result::OK) {
400 ret = OK;
401 callback(writeStatus);
402 } else {
403 ret = processReturn(cmdName, writeStatus.retval);
404 }
405 return ret;
406 }
407 if (ret == -EAGAIN || ret == -EINTR) {
408 // Spurious wakeup. This normally retries no more than once.
409 goto retry;
410 }
411 return ret;
412}
413
414status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
415 std::unique_ptr<CommandMQ> tempCommandMQ;
416 std::unique_ptr<DataMQ> tempDataMQ;
417 std::unique_ptr<StatusMQ> tempStatusMQ;
418 Result retval;
419 pid_t halThreadPid, halThreadTid;
420 Return<void> ret = mStream->prepareForWriting(
421 1, bufferSize,
422 [&](Result r,
423 const CommandMQ::Descriptor& commandMQ,
424 const DataMQ::Descriptor& dataMQ,
425 const StatusMQ::Descriptor& statusMQ,
426 const ThreadInfo& halThreadInfo) {
427 retval = r;
428 if (retval == Result::OK) {
429 tempCommandMQ.reset(new CommandMQ(commandMQ));
430 tempDataMQ.reset(new DataMQ(dataMQ));
431 tempStatusMQ.reset(new StatusMQ(statusMQ));
432 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
433 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
434 }
435 halThreadPid = halThreadInfo.pid;
436 halThreadTid = halThreadInfo.tid;
437 }
438 });
439 if (!ret.isOk() || retval != Result::OK) {
440 return processReturn("prepareForWriting", ret, retval);
441 }
442 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
443 !tempDataMQ || !tempDataMQ->isValid() ||
444 !tempStatusMQ || !tempStatusMQ->isValid() ||
445 !mEfGroup) {
446 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
447 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
448 "Command message queue for writing is invalid");
449 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
450 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
451 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
452 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
453 "Status message queue for writing is invalid");
454 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
455 return NO_INIT;
456 }
457 requestHalThreadPriority(halThreadPid, halThreadTid);
458
459 mCommandMQ = std::move(tempCommandMQ);
460 mDataMQ = std::move(tempDataMQ);
461 mStatusMQ = std::move(tempStatusMQ);
462 mWriterClient = gettid();
463 return OK;
464}
465
466status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
467 if (mStream == 0) return NO_INIT;
468 Result retval;
469 Return<void> ret = mStream->getRenderPosition(
470 [&](Result r, uint32_t d) {
471 retval = r;
472 if (retval == Result::OK) {
473 *dspFrames = d;
474 }
475 });
476 return processReturn("getRenderPosition", ret, retval);
477}
478
479status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
480 if (mStream == 0) return NO_INIT;
481 Result retval;
482 Return<void> ret = mStream->getNextWriteTimestamp(
483 [&](Result r, int64_t t) {
484 retval = r;
485 if (retval == Result::OK) {
486 *timestamp = t;
487 }
488 });
489 return processReturn("getRenderPosition", ret, retval);
490}
491
492status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
493 if (mStream == 0) return NO_INIT;
494 status_t status = processReturn(
495 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
496 if (status == OK) {
497 mCallback = callback;
498 }
499 return status;
500}
501
502status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
503 if (mStream == 0) return NO_INIT;
504 Return<void> ret = mStream->supportsPauseAndResume(
505 [&](bool p, bool r) {
506 *supportsPause = p;
507 *supportsResume = r;
508 });
509 return processReturn("supportsPauseAndResume", ret);
510}
511
512status_t StreamOutHalHidl::pause() {
513 if (mStream == 0) return NO_INIT;
514 return processReturn("pause", mStream->pause());
515}
516
517status_t StreamOutHalHidl::resume() {
518 if (mStream == 0) return NO_INIT;
519 return processReturn("pause", mStream->resume());
520}
521
522status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
523 if (mStream == 0) return NO_INIT;
524 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
525}
526
527status_t StreamOutHalHidl::drain(bool earlyNotify) {
528 if (mStream == 0) return NO_INIT;
529 return processReturn(
530 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
531}
532
533status_t StreamOutHalHidl::flush() {
534 if (mStream == 0) return NO_INIT;
535 return processReturn("pause", mStream->flush());
536}
537
538status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
539 if (mStream == 0) return NO_INIT;
540 if (mWriterClient == gettid() && mCommandMQ) {
541 return callWriterThread(
542 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
543 [&](const WriteStatus& writeStatus) {
544 *frames = writeStatus.reply.presentationPosition.frames;
545 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
546 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
547 });
548 } else {
549 Result retval;
550 Return<void> ret = mStream->getPresentationPosition(
551 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
552 retval = r;
553 if (retval == Result::OK) {
554 *frames = hidlFrames;
555 timestamp->tv_sec = hidlTimeStamp.tvSec;
556 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
557 }
558 });
559 return processReturn("getPresentationPosition", ret, retval);
560 }
561}
562
563void StreamOutHalHidl::onWriteReady() {
564 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
565 if (callback == 0) return;
566 ALOGV("asyncCallback onWriteReady");
567 callback->onWriteReady();
568}
569
570void StreamOutHalHidl::onDrainReady() {
571 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
572 if (callback == 0) return;
573 ALOGV("asyncCallback onDrainReady");
574 callback->onDrainReady();
575}
576
577void StreamOutHalHidl::onError() {
578 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
579 if (callback == 0) return;
580 ALOGV("asyncCallback onError");
581 callback->onError();
582}
583
584
585StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
586 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
587}
588
589StreamInHalHidl::~StreamInHalHidl() {
590 if (mStream != 0) {
591 processReturn("close", mStream->close());
592 mStream.clear();
593 hardware::IPCThreadState::self()->flushCommands();
594 }
595 if (mEfGroup) {
596 EventFlag::deleteEventFlag(&mEfGroup);
597 }
598}
599
600status_t StreamInHalHidl::getFrameSize(size_t *size) {
601 if (mStream == 0) return NO_INIT;
602 return processReturn("getFrameSize", mStream->getFrameSize(), size);
603}
604
605status_t StreamInHalHidl::setGain(float gain) {
606 if (mStream == 0) return NO_INIT;
607 return processReturn("setGain", mStream->setGain(gain));
608}
609
610status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
611 if (mStream == 0) return NO_INIT;
612 *read = 0;
613
614 if (bytes == 0 && !mDataMQ) {
615 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
616 return OK;
617 }
618
619 status_t status;
620 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
621 return status;
622 }
623
624 ReadParameters params;
625 params.command = ReadCommand::READ;
626 params.params.read = bytes;
627 status = callReaderThread(params, "read",
628 [&](const ReadStatus& readStatus) {
629 const size_t availToRead = mDataMQ->availableToRead();
630 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
631 ALOGE("data message queue read failed for \"read\"");
632 }
633 ALOGW_IF(availToRead != readStatus.reply.read,
634 "HAL read report inconsistent: mq = %d, status = %d",
635 (int32_t)availToRead, (int32_t)readStatus.reply.read);
636 *read = readStatus.reply.read;
637 });
638 mStreamPowerLog.log(buffer, *read);
639 return status;
640}
641
642status_t StreamInHalHidl::callReaderThread(
643 const ReadParameters& params, const char* cmdName,
644 StreamInHalHidl::ReaderCallback callback) {
645 if (!mCommandMQ->write(&params)) {
646 ALOGW("command message queue write failed");
647 return -EAGAIN;
648 }
649 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
650
651 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
652 uint32_t efState = 0;
653retry:
654 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
655 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
656 ReadStatus readStatus;
657 readStatus.retval = Result::NOT_INITIALIZED;
658 if (!mStatusMQ->read(&readStatus)) {
659 ALOGE("status message read failed for \"%s\"", cmdName);
660 }
661 if (readStatus.retval == Result::OK) {
662 ret = OK;
663 callback(readStatus);
664 } else {
665 ret = processReturn(cmdName, readStatus.retval);
666 }
667 return ret;
668 }
669 if (ret == -EAGAIN || ret == -EINTR) {
670 // Spurious wakeup. This normally retries no more than once.
671 goto retry;
672 }
673 return ret;
674}
675
676status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
677 std::unique_ptr<CommandMQ> tempCommandMQ;
678 std::unique_ptr<DataMQ> tempDataMQ;
679 std::unique_ptr<StatusMQ> tempStatusMQ;
680 Result retval;
681 pid_t halThreadPid, halThreadTid;
682 Return<void> ret = mStream->prepareForReading(
683 1, bufferSize,
684 [&](Result r,
685 const CommandMQ::Descriptor& commandMQ,
686 const DataMQ::Descriptor& dataMQ,
687 const StatusMQ::Descriptor& statusMQ,
688 const ThreadInfo& halThreadInfo) {
689 retval = r;
690 if (retval == Result::OK) {
691 tempCommandMQ.reset(new CommandMQ(commandMQ));
692 tempDataMQ.reset(new DataMQ(dataMQ));
693 tempStatusMQ.reset(new StatusMQ(statusMQ));
694 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
695 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
696 }
697 halThreadPid = halThreadInfo.pid;
698 halThreadTid = halThreadInfo.tid;
699 }
700 });
701 if (!ret.isOk() || retval != Result::OK) {
702 return processReturn("prepareForReading", ret, retval);
703 }
704 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
705 !tempDataMQ || !tempDataMQ->isValid() ||
706 !tempStatusMQ || !tempStatusMQ->isValid() ||
707 !mEfGroup) {
708 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
709 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
710 "Command message queue for writing is invalid");
711 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
712 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
713 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
714 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
715 "Status message queue for reading is invalid");
716 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
717 return NO_INIT;
718 }
719 requestHalThreadPriority(halThreadPid, halThreadTid);
720
721 mCommandMQ = std::move(tempCommandMQ);
722 mDataMQ = std::move(tempDataMQ);
723 mStatusMQ = std::move(tempStatusMQ);
724 mReaderClient = gettid();
725 return OK;
726}
727
728status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
729 if (mStream == 0) return NO_INIT;
730 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
731}
732
733status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
734 if (mStream == 0) return NO_INIT;
735 if (mReaderClient == gettid() && mCommandMQ) {
736 ReadParameters params;
737 params.command = ReadCommand::GET_CAPTURE_POSITION;
738 return callReaderThread(params, "getCapturePosition",
739 [&](const ReadStatus& readStatus) {
740 *frames = readStatus.reply.capturePosition.frames;
741 *time = readStatus.reply.capturePosition.time;
742 });
743 } else {
744 Result retval;
745 Return<void> ret = mStream->getCapturePosition(
746 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
747 retval = r;
748 if (retval == Result::OK) {
749 *frames = hidlFrames;
750 *time = hidlTime;
751 }
752 });
753 return processReturn("getCapturePosition", ret, retval);
754 }
755}
756
Kevin Rocard2390b5d2018-02-28 14:36:53 -0800757} // namespace V4_0
Kevin Rocardd4de2882018-02-28 14:33:38 -0800758} // namespace android