blob: 5943e225f0f32ee05d0b4ebcc62d5856ec28522b [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),
245 mGetPresentationPositionNotSupported(false), mPPosFromWriteObtained(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)) {
304 WriteStatus writeStatus = { Result::NOT_INITIALIZED, 0, 0, { 0, 0 } };
305 mStatusMQ->read(&writeStatus);
306 if (writeStatus.retval == Result::OK) {
307 status = OK;
308 *written = writeStatus.written;
309 mPPosFromWriteFrames = writeStatus.frames;
310 mPPosFromWriteTS.tv_sec = writeStatus.timeStamp.tvSec;
311 mPPosFromWriteTS.tv_nsec = writeStatus.timeStamp.tvNSec;
312 struct timespec timeNow;
313 clock_gettime(CLOCK_MONOTONIC, &timeNow);
314 mPPosFromWriteObtained = timeNow.tv_sec * 1000000 + timeNow.tv_nsec / 1000;
315 } else {
316 status = processReturn("write", writeStatus.retval);
317 }
318 return status;
319 }
320 if (ret == -EAGAIN) {
321 // This normally retries no more than once.
322 goto retry;
323 }
324 return ret;
325}
326
327status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
328 std::unique_ptr<DataMQ> tempDataMQ;
329 std::unique_ptr<StatusMQ> tempStatusMQ;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800330 Result retval;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800331 Return<void> ret = mStream->prepareForWriting(
332 1, bufferSize, ThreadPriority(mHalThreadPriority),
333 [&](Result r,
334 const MQDescriptorSync<uint8_t>& dataMQ,
335 const MQDescriptorSync<WriteStatus>& statusMQ) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800336 retval = r;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800337 if (retval == Result::OK) {
338 tempDataMQ.reset(new DataMQ(dataMQ));
339 tempStatusMQ.reset(new StatusMQ(statusMQ));
340 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
341 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
342 }
343 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800344 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800345 if (!ret.isOk() || retval != Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800346 return processReturn("prepareForWriting", ret, retval);
347 }
348 if (!tempDataMQ || !tempDataMQ->isValid() || !tempStatusMQ || !tempStatusMQ->isValid()
349 || !mEfGroup) {
350 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
351 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
352 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
353 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
354 "Status message queue for writing is invalid");
355 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
356 return NO_INIT;
357 }
358 mDataMQ = std::move(tempDataMQ);
359 mStatusMQ = std::move(tempStatusMQ);
360 return OK;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800361}
362
363status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
364 if (mStream == 0) return NO_INIT;
365 Result retval;
366 Return<void> ret = mStream->getRenderPosition(
367 [&](Result r, uint32_t d) {
368 retval = r;
369 if (retval == Result::OK) {
370 *dspFrames = d;
371 }
372 });
373 return processReturn("getRenderPosition", ret, retval);
374}
375
376status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
377 if (mStream == 0) return NO_INIT;
378 Result retval;
379 Return<void> ret = mStream->getNextWriteTimestamp(
380 [&](Result r, int64_t t) {
381 retval = r;
382 if (retval == Result::OK) {
383 *timestamp = t;
384 }
385 });
386 return processReturn("getRenderPosition", ret, retval);
387}
388
389status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
390 if (mStream == 0) return NO_INIT;
391 status_t status = processReturn(
392 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
393 if (status == OK) {
394 mCallback = callback;
395 }
396 return status;
397}
398
399status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
400 if (mStream == 0) return NO_INIT;
401 Return<void> ret = mStream->supportsPauseAndResume(
402 [&](bool p, bool r) {
403 *supportsPause = p;
404 *supportsResume = r;
405 });
406 return processReturn("supportsPauseAndResume", ret);
407}
408
409status_t StreamOutHalHidl::pause() {
410 if (mStream == 0) return NO_INIT;
411 return processReturn("pause", mStream->pause());
412}
413
414status_t StreamOutHalHidl::resume() {
415 if (mStream == 0) return NO_INIT;
416 return processReturn("pause", mStream->resume());
417}
418
419status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
420 if (mStream == 0) return NO_INIT;
421 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
422}
423
424status_t StreamOutHalHidl::drain(bool earlyNotify) {
425 if (mStream == 0) return NO_INIT;
426 return processReturn(
427 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
428}
429
430status_t StreamOutHalHidl::flush() {
431 if (mStream == 0) return NO_INIT;
432 return processReturn("pause", mStream->flush());
433}
434
435status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
436 if (mStream == 0) return NO_INIT;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800437 if (mGetPresentationPositionNotSupported) return INVALID_OPERATION;
438 struct timespec timeNow;
439 clock_gettime(CLOCK_MONOTONIC, &timeNow);
440 uint64_t timeStampNow = timeNow.tv_sec * 1000000 + timeNow.tv_nsec / 1000;
441 if (timeStampNow - mPPosFromWriteObtained <= 1000) {
442 // No more than 1 ms passed since the last write, use cached result to avoid binder calls.
443 *frames = mPPosFromWriteFrames;
444 timestamp->tv_sec = mPPosFromWriteTS.tv_sec;
445 timestamp->tv_nsec = mPPosFromWriteTS.tv_nsec;
446 return OK;
447 }
448
Mikhail Naganovf558e022016-11-14 17:45:17 -0800449 Result retval;
450 Return<void> ret = mStream->getPresentationPosition(
451 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
452 retval = r;
453 if (retval == Result::OK) {
454 *frames = hidlFrames;
455 timestamp->tv_sec = hidlTimeStamp.tvSec;
456 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
457 }
458 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800459 if (ret.isOk() && retval == Result::NOT_SUPPORTED) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800460 mGetPresentationPositionNotSupported = true;
461 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800462 return processReturn("getPresentationPosition", ret, retval);
463}
464
465void StreamOutHalHidl::onWriteReady() {
466 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
467 if (callback == 0) return;
468 ALOGV("asyncCallback onWriteReady");
469 callback->onWriteReady();
470}
471
472void StreamOutHalHidl::onDrainReady() {
473 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
474 if (callback == 0) return;
475 ALOGV("asyncCallback onDrainReady");
476 callback->onDrainReady();
477}
478
479void StreamOutHalHidl::onError() {
480 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
481 if (callback == 0) return;
482 ALOGV("asyncCallback onError");
483 callback->onError();
484}
485
486
487StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800488 : StreamHalHidl(stream.get()), mStream(stream), mEfGroup(nullptr) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800489}
490
491StreamInHalHidl::~StreamInHalHidl() {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800492 if (mStream != 0) {
493 processReturn("close", mStream->close());
494 }
495 if (mEfGroup) {
496 EventFlag::deleteEventFlag(&mEfGroup);
497 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800498}
499
500status_t StreamInHalHidl::getFrameSize(size_t *size) {
501 if (mStream == 0) return NO_INIT;
502 return processReturn("getFrameSize", mStream->getFrameSize(), size);
503}
504
505status_t StreamInHalHidl::setGain(float gain) {
506 if (mStream == 0) return NO_INIT;
507 return processReturn("setGain", mStream->setGain(gain));
508}
509
510status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
511 if (mStream == 0) return NO_INIT;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800512 *read = 0;
513
514 if (bytes == 0 && !mDataMQ) {
515 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
516 return OK;
517 }
518
519 status_t status;
520 if (!mDataMQ) {
521 if ((status = prepareForReading(bytes)) != OK) return status;
522 // Trigger the first read.
523 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
524 }
525
526 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
527 uint32_t efState = 0;
528retry:
529 status_t ret = mEfGroup->wait(
530 static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState, NS_PER_SEC);
531 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
532 ReadStatus readStatus = { Result::NOT_INITIALIZED, 0 };
533 const size_t availToRead = mDataMQ->availableToRead();
534 if (bytes > availToRead) { bytes = availToRead; }
535 mDataMQ->read(static_cast<uint8_t*>(buffer), bytes);
536 mStatusMQ->read(&readStatus);
537 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
538 if (readStatus.retval == Result::OK) {
539 ALOGW_IF(availToRead != readStatus.read,
540 "HAL read report inconsistent: mq = %d, status = %d",
541 (int32_t)availToRead, (int32_t)readStatus.read);
542 *read = readStatus.read;
543 } else {
544 status = processReturn("read", readStatus.retval);
545 }
546 return status;
547 }
548 if (ret == -EAGAIN) {
549 // This normally retries no more than once.
550 goto retry;
551 }
552 return ret;
553}
554
555status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
556 std::unique_ptr<DataMQ> tempDataMQ;
557 std::unique_ptr<StatusMQ> tempStatusMQ;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800558 Result retval;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800559 Return<void> ret = mStream->prepareForReading(
560 1, bufferSize, ThreadPriority(mHalThreadPriority),
561 [&](Result r,
562 const MQDescriptorSync<uint8_t>& dataMQ,
563 const MQDescriptorSync<ReadStatus>& statusMQ) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800564 retval = r;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800565 if (retval == Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800566 tempDataMQ.reset(new DataMQ(dataMQ));
567 tempStatusMQ.reset(new StatusMQ(statusMQ));
568 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
569 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
570 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800571 }
572 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800573 if (!ret.isOk() || retval != Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800574 return processReturn("prepareForReading", ret, retval);
575 }
576 if (!tempDataMQ || !tempDataMQ->isValid() || !tempStatusMQ || !tempStatusMQ->isValid()
577 || !mEfGroup) {
578 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
579 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
580 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
581 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
582 "Status message queue for reading is invalid");
583 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
584 return NO_INIT;
585 }
586 mDataMQ = std::move(tempDataMQ);
587 mStatusMQ = std::move(tempStatusMQ);
588 return OK;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800589}
590
591status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
592 if (mStream == 0) return NO_INIT;
593 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
594}
595
596status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
597 if (mStream == 0) return NO_INIT;
598 Result retval;
599 Return<void> ret = mStream->getCapturePosition(
600 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
601 retval = r;
602 if (retval == Result::OK) {
603 *frames = hidlFrames;
604 *time = hidlTime;
605 }
606 });
607 return processReturn("getCapturePosition", ret, retval);
608}
609
610} // namespace android