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