blob: 9ee8fa80b00fdbfa6317e265f9d8b48bc63aa8f4 [file] [log] [blame]
Mikhail Naganovf558e022016-11-14 17:45:17 -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
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -080017#include <time.h>
18
Mikhail Naganovf558e022016-11-14 17:45:17 -080019#define LOG_TAG "StreamHalHidl"
20//#define LOG_NDEBUG 0
21
22#include <android/hardware/audio/2.0/IStreamOutCallback.h>
23#include <utils/Log.h>
24
25#include "DeviceHalHidl.h"
26#include "EffectHalHidl.h"
27#include "StreamHalHidl.h"
28
29using ::android::hardware::audio::common::V2_0::AudioChannelMask;
30using ::android::hardware::audio::common::V2_0::AudioFormat;
31using ::android::hardware::audio::V2_0::AudioDrain;
32using ::android::hardware::audio::V2_0::IStreamOutCallback;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -080033using ::android::hardware::audio::V2_0::MessageQueueFlagBits;
Eric Laurentaf35aad2016-12-15 14:25:36 -080034using ::android::hardware::audio::V2_0::MmapBufferInfo;
35using ::android::hardware::audio::V2_0::MmapPosition;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -080036using ::android::hardware::audio::V2_0::ParameterValue;
37using ::android::hardware::audio::V2_0::Result;
38using ::android::hardware::audio::V2_0::ThreadPriority;
39using ::android::hardware::audio::V2_0::TimeSpec;
40using ::android::hardware::MQDescriptorSync;
Mikhail Naganovf558e022016-11-14 17:45:17 -080041using ::android::hardware::Return;
42using ::android::hardware::Void;
43
44namespace android {
45
46StreamHalHidl::StreamHalHidl(IStream *stream)
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -080047 : ConversionHelperHidl("Stream"),
48 mHalThreadPriority(static_cast<int>(ThreadPriority::NORMAL)),
49 mStream(stream) {
Mikhail Naganovf558e022016-11-14 17:45:17 -080050}
51
52StreamHalHidl::~StreamHalHidl() {
53 mStream = nullptr;
54}
55
56status_t StreamHalHidl::getSampleRate(uint32_t *rate) {
57 if (!mStream) return NO_INIT;
58 return processReturn("getSampleRate", mStream->getSampleRate(), rate);
59}
60
61status_t StreamHalHidl::getBufferSize(size_t *size) {
62 if (!mStream) return NO_INIT;
63 return processReturn("getBufferSize", mStream->getBufferSize(), size);
64}
65
66status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) {
67 if (!mStream) return NO_INIT;
68 return processReturn("getChannelMask", mStream->getChannelMask(), mask);
69}
70
71status_t StreamHalHidl::getFormat(audio_format_t *format) {
72 if (!mStream) return NO_INIT;
73 return processReturn("getFormat", mStream->getFormat(), format);
74}
75
76status_t StreamHalHidl::getAudioProperties(
77 uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) {
78 if (!mStream) return NO_INIT;
79 Return<void> ret = mStream->getAudioProperties(
80 [&](uint32_t sr, AudioChannelMask m, AudioFormat f) {
81 *sampleRate = sr;
82 *mask = static_cast<audio_channel_mask_t>(m);
83 *format = static_cast<audio_format_t>(f);
84 });
85 return processReturn("getAudioProperties", ret);
86}
87
88status_t StreamHalHidl::setParameters(const String8& kvPairs) {
89 if (!mStream) return NO_INIT;
90 hidl_vec<ParameterValue> hidlParams;
91 status_t status = parametersFromHal(kvPairs, &hidlParams);
92 if (status != OK) return status;
93 return processReturn("setParameters", mStream->setParameters(hidlParams));
94}
95
96status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
97 values->clear();
98 if (!mStream) return NO_INIT;
99 hidl_vec<hidl_string> hidlKeys;
100 status_t status = keysFromHal(keys, &hidlKeys);
101 if (status != OK) return status;
102 Result retval;
103 Return<void> ret = mStream->getParameters(
104 hidlKeys,
105 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
106 retval = r;
107 if (retval == Result::OK) {
108 parametersToHal(parameters, values);
109 }
110 });
111 return processReturn("getParameters", ret, retval);
112}
113
114status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
115 if (!mStream) return NO_INIT;
116 return processReturn("addEffect", mStream->addEffect(
117 static_cast<EffectHalHidl*>(effect.get())->effectId()));
118}
119
120status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
121 if (!mStream) return NO_INIT;
122 return processReturn("removeEffect", mStream->removeEffect(
123 static_cast<EffectHalHidl*>(effect.get())->effectId()));
124}
125
126status_t StreamHalHidl::standby() {
127 if (!mStream) return NO_INIT;
128 return processReturn("standby", mStream->standby());
129}
130
131status_t StreamHalHidl::dump(int fd) {
132 if (!mStream) return NO_INIT;
133 native_handle_t* hidlHandle = native_handle_create(1, 0);
134 hidlHandle->data[0] = fd;
135 Return<void> ret = mStream->debugDump(hidlHandle);
136 native_handle_delete(hidlHandle);
137 return processReturn("dump", ret);
138}
139
Eric Laurentaf35aad2016-12-15 14:25:36 -0800140status_t StreamHalHidl::start() {
141 if (!mStream) return NO_INIT;
142 return processReturn("start", mStream->start());
143}
144
145status_t StreamHalHidl::stop() {
146 if (!mStream) return NO_INIT;
147 return processReturn("stop", mStream->stop());
148}
149
150status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
151 struct audio_mmap_buffer_info *info) {
152 Result retval;
153 Return<void> ret = mStream->createMmapBuffer(
154 minSizeFrames,
155 [&](Result r, const MmapBufferInfo& hidlInfo) {
156 retval = r;
157 if (retval == Result::OK) {
Eric Laurentb8753072016-12-21 12:04:10 -0800158 const native_handle *handle = hidlInfo.sharedMemory.handle();
Eric Laurentaf35aad2016-12-15 14:25:36 -0800159 if (handle->numFds > 0) {
160 info->shared_memory_fd = dup(handle->data[0]);
161 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
162 info->burst_size_frames = hidlInfo.burstSizeFrames;
163 // info->shared_memory_address is not needed in HIDL context
164 info->shared_memory_address = NULL;
165 } else {
166 retval = Result::NOT_INITIALIZED;
167 }
168 }
169 });
170 return processReturn("createMmapBuffer", ret, retval);
171}
172
173status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
174 Result retval;
175 Return<void> ret = mStream->getMmapPosition(
176 [&](Result r, const MmapPosition& hidlPosition) {
177 retval = r;
178 if (retval == Result::OK) {
179 position->time_nanoseconds = hidlPosition.timeNanoseconds;
180 position->position_frames = hidlPosition.positionFrames;
181 }
182 });
183 return processReturn("getMmapPosition", ret, retval);
184}
Mikhail Naganovf558e022016-11-14 17:45:17 -0800185
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800186status_t StreamHalHidl::setHalThreadPriority(int priority) {
187 mHalThreadPriority = priority;
188 return OK;
189}
190
Mikhail Naganovf558e022016-11-14 17:45:17 -0800191namespace {
192
193/* Notes on callback ownership.
194
195This is how (Hw)Binder ownership model looks like. The server implementation
196is owned by Binder framework (via sp<>). Proxies are owned by clients.
197When the last proxy disappears, Binder framework releases the server impl.
198
199Thus, it is not needed to keep any references to StreamOutCallback (this is
200the server impl) -- it will live as long as HAL server holds a strong ref to
201IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
202from the destructor of StreamOutHalHidl.
203
204The callback only keeps a weak reference to the stream. The stream is owned
205by AudioFlinger.
206
207*/
208
209struct StreamOutCallback : public IStreamOutCallback {
210 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
211
212 // IStreamOutCallback implementation
213 Return<void> onWriteReady() override {
214 sp<StreamOutHalHidl> stream = mStream.promote();
215 if (stream != 0) {
216 stream->onWriteReady();
217 }
218 return Void();
219 }
220
221 Return<void> onDrainReady() override {
222 sp<StreamOutHalHidl> stream = mStream.promote();
223 if (stream != 0) {
224 stream->onDrainReady();
225 }
226 return Void();
227 }
228
229 Return<void> onError() override {
230 sp<StreamOutHalHidl> stream = mStream.promote();
231 if (stream != 0) {
232 stream->onError();
233 }
234 return Void();
235 }
236
237 private:
238 wp<StreamOutHalHidl> mStream;
239};
240
241} // namespace
242
243StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800244 : StreamHalHidl(stream.get()), mStream(stream), mEfGroup(nullptr),
Mikhail Naganovd6351992017-01-12 09:35:16 -0800245 mGetPresentationPositionNotSupported(false), mPPosFromWrite{ 0, OK, 0, { 0, 0 } } {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800246}
247
248StreamOutHalHidl::~StreamOutHalHidl() {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800249 if (mStream != 0) {
250 if (mCallback.unsafe_get()) {
251 processReturn("clearCallback", mStream->clearCallback());
252 }
253 processReturn("close", mStream->close());
Mikhail Naganovf558e022016-11-14 17:45:17 -0800254 }
255 mCallback.clear();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800256 if (mEfGroup) {
257 EventFlag::deleteEventFlag(&mEfGroup);
258 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800259}
260
261status_t StreamOutHalHidl::getFrameSize(size_t *size) {
262 if (mStream == 0) return NO_INIT;
263 return processReturn("getFrameSize", mStream->getFrameSize(), size);
264}
265
266status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
267 if (mStream == 0) return NO_INIT;
268 return processReturn("getLatency", mStream->getLatency(), latency);
269}
270
271status_t StreamOutHalHidl::setVolume(float left, float right) {
272 if (mStream == 0) return NO_INIT;
273 return processReturn("setVolume", mStream->setVolume(left, right));
274}
275
276status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
277 if (mStream == 0) return NO_INIT;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800278 *written = 0;
279
280 if (bytes == 0 && !mDataMQ) {
281 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
282 ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes");
283 return OK;
284 }
285
286 status_t status;
287 if (!mDataMQ && (status = prepareForWriting(bytes)) != OK) {
288 return status;
289 }
290
291 const size_t availBytes = mDataMQ->availableToWrite();
292 if (bytes > availBytes) { bytes = availBytes; }
293 if (!mDataMQ->write(static_cast<const uint8_t*>(buffer), bytes)) {
294 ALOGW("data message queue write failed");
295 }
296 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
297
298 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
299 uint32_t efState = 0;
300retry:
301 status_t ret = mEfGroup->wait(
302 static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState, NS_PER_SEC);
303 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
Mikhail Naganovd6351992017-01-12 09:35:16 -0800304 WriteStatus writeStatus =
305 { Result::NOT_INITIALIZED, 0, Result::NOT_INITIALIZED, 0, { 0, 0 } };
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800306 mStatusMQ->read(&writeStatus);
Mikhail Naganovd6351992017-01-12 09:35:16 -0800307 if (writeStatus.writeRetval == Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800308 status = OK;
309 *written = writeStatus.written;
Mikhail Naganovd6351992017-01-12 09:35:16 -0800310 mPPosFromWrite.status = processReturn(
311 "get_presentation_position", writeStatus.presentationPositionRetval);
312 if (mPPosFromWrite.status == OK) {
313 mPPosFromWrite.frames = writeStatus.frames;
314 mPPosFromWrite.ts.tv_sec = writeStatus.timeStamp.tvSec;
315 mPPosFromWrite.ts.tv_nsec = writeStatus.timeStamp.tvNSec;
316 }
317 mPPosFromWrite.obtained = getCurrentTimeMs();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800318 } else {
Mikhail Naganovd6351992017-01-12 09:35:16 -0800319 status = processReturn("write", writeStatus.writeRetval);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800320 }
321 return status;
322 }
323 if (ret == -EAGAIN) {
324 // This normally retries no more than once.
325 goto retry;
326 }
327 return ret;
328}
329
Mikhail Naganovd6351992017-01-12 09:35:16 -0800330uint64_t StreamOutHalHidl::getCurrentTimeMs() {
331 struct timespec timeNow;
332 clock_gettime(CLOCK_MONOTONIC, &timeNow);
333 return timeNow.tv_sec * 1000000 + timeNow.tv_nsec / 1000;
334}
335
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800336status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
337 std::unique_ptr<DataMQ> tempDataMQ;
338 std::unique_ptr<StatusMQ> tempStatusMQ;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800339 Result retval;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800340 Return<void> ret = mStream->prepareForWriting(
341 1, bufferSize, ThreadPriority(mHalThreadPriority),
342 [&](Result r,
Hridya Valsaraju085ae9a2017-01-10 09:42:17 -0800343 const DataMQ::Descriptor& dataMQ,
344 const StatusMQ::Descriptor& statusMQ) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800345 retval = r;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800346 if (retval == Result::OK) {
347 tempDataMQ.reset(new DataMQ(dataMQ));
348 tempStatusMQ.reset(new StatusMQ(statusMQ));
349 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
350 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
351 }
352 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800353 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800354 if (!ret.isOk() || retval != Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800355 return processReturn("prepareForWriting", ret, retval);
356 }
357 if (!tempDataMQ || !tempDataMQ->isValid() || !tempStatusMQ || !tempStatusMQ->isValid()
358 || !mEfGroup) {
359 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
360 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
361 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
362 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
363 "Status message queue for writing is invalid");
364 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
365 return NO_INIT;
366 }
367 mDataMQ = std::move(tempDataMQ);
368 mStatusMQ = std::move(tempStatusMQ);
369 return OK;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800370}
371
372status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
373 if (mStream == 0) return NO_INIT;
374 Result retval;
375 Return<void> ret = mStream->getRenderPosition(
376 [&](Result r, uint32_t d) {
377 retval = r;
378 if (retval == Result::OK) {
379 *dspFrames = d;
380 }
381 });
382 return processReturn("getRenderPosition", ret, retval);
383}
384
385status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
386 if (mStream == 0) return NO_INIT;
387 Result retval;
388 Return<void> ret = mStream->getNextWriteTimestamp(
389 [&](Result r, int64_t t) {
390 retval = r;
391 if (retval == Result::OK) {
392 *timestamp = t;
393 }
394 });
395 return processReturn("getRenderPosition", ret, retval);
396}
397
398status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
399 if (mStream == 0) return NO_INIT;
400 status_t status = processReturn(
401 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
402 if (status == OK) {
403 mCallback = callback;
404 }
405 return status;
406}
407
408status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
409 if (mStream == 0) return NO_INIT;
410 Return<void> ret = mStream->supportsPauseAndResume(
411 [&](bool p, bool r) {
412 *supportsPause = p;
413 *supportsResume = r;
414 });
415 return processReturn("supportsPauseAndResume", ret);
416}
417
418status_t StreamOutHalHidl::pause() {
419 if (mStream == 0) return NO_INIT;
420 return processReturn("pause", mStream->pause());
421}
422
423status_t StreamOutHalHidl::resume() {
424 if (mStream == 0) return NO_INIT;
425 return processReturn("pause", mStream->resume());
426}
427
428status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
429 if (mStream == 0) return NO_INIT;
430 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
431}
432
433status_t StreamOutHalHidl::drain(bool earlyNotify) {
434 if (mStream == 0) return NO_INIT;
435 return processReturn(
436 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
437}
438
439status_t StreamOutHalHidl::flush() {
440 if (mStream == 0) return NO_INIT;
441 return processReturn("pause", mStream->flush());
442}
443
444status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
445 if (mStream == 0) return NO_INIT;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800446 if (mGetPresentationPositionNotSupported) return INVALID_OPERATION;
Mikhail Naganovd6351992017-01-12 09:35:16 -0800447 if (getCurrentTimeMs() - mPPosFromWrite.obtained <= 1000) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800448 // No more than 1 ms passed since the last write, use cached result to avoid binder calls.
Mikhail Naganovd6351992017-01-12 09:35:16 -0800449 if (mPPosFromWrite.status == OK) {
450 *frames = mPPosFromWrite.frames;
451 timestamp->tv_sec = mPPosFromWrite.ts.tv_sec;
452 timestamp->tv_nsec = mPPosFromWrite.ts.tv_nsec;
453 }
454 return mPPosFromWrite.status;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800455 }
456
Mikhail Naganovf558e022016-11-14 17:45:17 -0800457 Result retval;
458 Return<void> ret = mStream->getPresentationPosition(
459 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
460 retval = r;
461 if (retval == Result::OK) {
462 *frames = hidlFrames;
463 timestamp->tv_sec = hidlTimeStamp.tvSec;
464 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
465 }
466 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800467 if (ret.isOk() && retval == Result::NOT_SUPPORTED) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800468 mGetPresentationPositionNotSupported = true;
469 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800470 return processReturn("getPresentationPosition", ret, retval);
471}
472
473void StreamOutHalHidl::onWriteReady() {
474 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
475 if (callback == 0) return;
476 ALOGV("asyncCallback onWriteReady");
477 callback->onWriteReady();
478}
479
480void StreamOutHalHidl::onDrainReady() {
481 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
482 if (callback == 0) return;
483 ALOGV("asyncCallback onDrainReady");
484 callback->onDrainReady();
485}
486
487void StreamOutHalHidl::onError() {
488 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
489 if (callback == 0) return;
490 ALOGV("asyncCallback onError");
491 callback->onError();
492}
493
494
495StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800496 : StreamHalHidl(stream.get()), mStream(stream), mEfGroup(nullptr) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800497}
498
499StreamInHalHidl::~StreamInHalHidl() {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800500 if (mStream != 0) {
501 processReturn("close", mStream->close());
502 }
503 if (mEfGroup) {
504 EventFlag::deleteEventFlag(&mEfGroup);
505 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800506}
507
508status_t StreamInHalHidl::getFrameSize(size_t *size) {
509 if (mStream == 0) return NO_INIT;
510 return processReturn("getFrameSize", mStream->getFrameSize(), size);
511}
512
513status_t StreamInHalHidl::setGain(float gain) {
514 if (mStream == 0) return NO_INIT;
515 return processReturn("setGain", mStream->setGain(gain));
516}
517
518status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
519 if (mStream == 0) return NO_INIT;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800520 *read = 0;
521
522 if (bytes == 0 && !mDataMQ) {
523 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
524 return OK;
525 }
526
527 status_t status;
528 if (!mDataMQ) {
529 if ((status = prepareForReading(bytes)) != OK) return status;
530 // Trigger the first read.
531 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
532 }
533
534 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
535 uint32_t efState = 0;
536retry:
537 status_t ret = mEfGroup->wait(
538 static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState, NS_PER_SEC);
539 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
540 ReadStatus readStatus = { Result::NOT_INITIALIZED, 0 };
541 const size_t availToRead = mDataMQ->availableToRead();
542 if (bytes > availToRead) { bytes = availToRead; }
543 mDataMQ->read(static_cast<uint8_t*>(buffer), bytes);
544 mStatusMQ->read(&readStatus);
545 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
546 if (readStatus.retval == Result::OK) {
547 ALOGW_IF(availToRead != readStatus.read,
548 "HAL read report inconsistent: mq = %d, status = %d",
549 (int32_t)availToRead, (int32_t)readStatus.read);
550 *read = readStatus.read;
551 } else {
552 status = processReturn("read", readStatus.retval);
553 }
554 return status;
555 }
556 if (ret == -EAGAIN) {
557 // This normally retries no more than once.
558 goto retry;
559 }
560 return ret;
561}
562
563status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
564 std::unique_ptr<DataMQ> tempDataMQ;
565 std::unique_ptr<StatusMQ> tempStatusMQ;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800566 Result retval;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800567 Return<void> ret = mStream->prepareForReading(
568 1, bufferSize, ThreadPriority(mHalThreadPriority),
569 [&](Result r,
Hridya Valsaraju085ae9a2017-01-10 09:42:17 -0800570 const DataMQ::Descriptor& dataMQ,
571 const StatusMQ::Descriptor& statusMQ) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800572 retval = r;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800573 if (retval == Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800574 tempDataMQ.reset(new DataMQ(dataMQ));
575 tempStatusMQ.reset(new StatusMQ(statusMQ));
576 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
577 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
578 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800579 }
580 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800581 if (!ret.isOk() || retval != Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800582 return processReturn("prepareForReading", ret, retval);
583 }
584 if (!tempDataMQ || !tempDataMQ->isValid() || !tempStatusMQ || !tempStatusMQ->isValid()
585 || !mEfGroup) {
586 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
587 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
588 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
589 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
590 "Status message queue for reading is invalid");
591 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
592 return NO_INIT;
593 }
594 mDataMQ = std::move(tempDataMQ);
595 mStatusMQ = std::move(tempStatusMQ);
596 return OK;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800597}
598
599status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
600 if (mStream == 0) return NO_INIT;
601 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
602}
603
604status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
605 if (mStream == 0) return NO_INIT;
606 Result retval;
607 Return<void> ret = mStream->getCapturePosition(
608 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
609 retval = r;
610 if (retval == Result::OK) {
611 *frames = hidlFrames;
612 *time = hidlTime;
613 }
614 });
615 return processReturn("getCapturePosition", ret, retval);
616}
617
618} // namespace android