blob: 36ea1be26eccaed608d283c833f0afd78c844003 [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
17#define LOG_TAG "StreamHalHidl"
18//#define LOG_NDEBUG 0
19
20#include <android/hardware/audio/2.0/IStreamOutCallback.h>
21#include <utils/Log.h>
22
23#include "DeviceHalHidl.h"
24#include "EffectHalHidl.h"
25#include "StreamHalHidl.h"
26
27using ::android::hardware::audio::common::V2_0::AudioChannelMask;
28using ::android::hardware::audio::common::V2_0::AudioFormat;
29using ::android::hardware::audio::V2_0::AudioDrain;
30using ::android::hardware::audio::V2_0::IStreamOutCallback;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -080031using ::android::hardware::audio::V2_0::MessageQueueFlagBits;
Eric Laurentaf35aad2016-12-15 14:25:36 -080032using ::android::hardware::audio::V2_0::MmapBufferInfo;
33using ::android::hardware::audio::V2_0::MmapPosition;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -080034using ::android::hardware::audio::V2_0::ParameterValue;
35using ::android::hardware::audio::V2_0::Result;
36using ::android::hardware::audio::V2_0::ThreadPriority;
37using ::android::hardware::audio::V2_0::TimeSpec;
38using ::android::hardware::MQDescriptorSync;
Mikhail Naganovf558e022016-11-14 17:45:17 -080039using ::android::hardware::Return;
40using ::android::hardware::Void;
Mikhail Naganovc8381902017-01-31 13:56:25 -080041using ReadCommand = ::android::hardware::audio::V2_0::IStreamIn::ReadCommand;
Mikhail Naganovf558e022016-11-14 17:45:17 -080042
43namespace android {
44
45StreamHalHidl::StreamHalHidl(IStream *stream)
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -080046 : ConversionHelperHidl("Stream"),
47 mHalThreadPriority(static_cast<int>(ThreadPriority::NORMAL)),
48 mStream(stream) {
Mikhail Naganovf558e022016-11-14 17:45:17 -080049}
50
51StreamHalHidl::~StreamHalHidl() {
52 mStream = nullptr;
53}
54
55status_t StreamHalHidl::getSampleRate(uint32_t *rate) {
56 if (!mStream) return NO_INIT;
57 return processReturn("getSampleRate", mStream->getSampleRate(), rate);
58}
59
60status_t StreamHalHidl::getBufferSize(size_t *size) {
61 if (!mStream) return NO_INIT;
62 return processReturn("getBufferSize", mStream->getBufferSize(), size);
63}
64
65status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) {
66 if (!mStream) return NO_INIT;
67 return processReturn("getChannelMask", mStream->getChannelMask(), mask);
68}
69
70status_t StreamHalHidl::getFormat(audio_format_t *format) {
71 if (!mStream) return NO_INIT;
72 return processReturn("getFormat", mStream->getFormat(), format);
73}
74
75status_t StreamHalHidl::getAudioProperties(
76 uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) {
77 if (!mStream) return NO_INIT;
78 Return<void> ret = mStream->getAudioProperties(
79 [&](uint32_t sr, AudioChannelMask m, AudioFormat f) {
80 *sampleRate = sr;
81 *mask = static_cast<audio_channel_mask_t>(m);
82 *format = static_cast<audio_format_t>(f);
83 });
84 return processReturn("getAudioProperties", ret);
85}
86
87status_t StreamHalHidl::setParameters(const String8& kvPairs) {
88 if (!mStream) return NO_INIT;
89 hidl_vec<ParameterValue> hidlParams;
90 status_t status = parametersFromHal(kvPairs, &hidlParams);
91 if (status != OK) return status;
92 return processReturn("setParameters", mStream->setParameters(hidlParams));
93}
94
95status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
96 values->clear();
97 if (!mStream) return NO_INIT;
98 hidl_vec<hidl_string> hidlKeys;
99 status_t status = keysFromHal(keys, &hidlKeys);
100 if (status != OK) return status;
101 Result retval;
102 Return<void> ret = mStream->getParameters(
103 hidlKeys,
104 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
105 retval = r;
106 if (retval == Result::OK) {
107 parametersToHal(parameters, values);
108 }
109 });
110 return processReturn("getParameters", ret, retval);
111}
112
113status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
114 if (!mStream) return NO_INIT;
115 return processReturn("addEffect", mStream->addEffect(
116 static_cast<EffectHalHidl*>(effect.get())->effectId()));
117}
118
119status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
120 if (!mStream) return NO_INIT;
121 return processReturn("removeEffect", mStream->removeEffect(
122 static_cast<EffectHalHidl*>(effect.get())->effectId()));
123}
124
125status_t StreamHalHidl::standby() {
126 if (!mStream) return NO_INIT;
127 return processReturn("standby", mStream->standby());
128}
129
130status_t StreamHalHidl::dump(int fd) {
131 if (!mStream) return NO_INIT;
132 native_handle_t* hidlHandle = native_handle_create(1, 0);
133 hidlHandle->data[0] = fd;
134 Return<void> ret = mStream->debugDump(hidlHandle);
135 native_handle_delete(hidlHandle);
136 return processReturn("dump", ret);
137}
138
Eric Laurentaf35aad2016-12-15 14:25:36 -0800139status_t StreamHalHidl::start() {
140 if (!mStream) return NO_INIT;
141 return processReturn("start", mStream->start());
142}
143
144status_t StreamHalHidl::stop() {
145 if (!mStream) return NO_INIT;
146 return processReturn("stop", mStream->stop());
147}
148
149status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
150 struct audio_mmap_buffer_info *info) {
151 Result retval;
152 Return<void> ret = mStream->createMmapBuffer(
153 minSizeFrames,
154 [&](Result r, const MmapBufferInfo& hidlInfo) {
155 retval = r;
156 if (retval == Result::OK) {
Eric Laurentb8753072016-12-21 12:04:10 -0800157 const native_handle *handle = hidlInfo.sharedMemory.handle();
Eric Laurentaf35aad2016-12-15 14:25:36 -0800158 if (handle->numFds > 0) {
159 info->shared_memory_fd = dup(handle->data[0]);
160 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
161 info->burst_size_frames = hidlInfo.burstSizeFrames;
162 // info->shared_memory_address is not needed in HIDL context
163 info->shared_memory_address = NULL;
164 } else {
165 retval = Result::NOT_INITIALIZED;
166 }
167 }
168 });
169 return processReturn("createMmapBuffer", ret, retval);
170}
171
172status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
173 Result retval;
174 Return<void> ret = mStream->getMmapPosition(
175 [&](Result r, const MmapPosition& hidlPosition) {
176 retval = r;
177 if (retval == Result::OK) {
178 position->time_nanoseconds = hidlPosition.timeNanoseconds;
179 position->position_frames = hidlPosition.positionFrames;
180 }
181 });
182 return processReturn("getMmapPosition", ret, retval);
183}
Mikhail Naganovf558e022016-11-14 17:45:17 -0800184
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800185status_t StreamHalHidl::setHalThreadPriority(int priority) {
186 mHalThreadPriority = priority;
187 return OK;
188}
189
Mikhail Naganovf558e022016-11-14 17:45:17 -0800190namespace {
191
192/* Notes on callback ownership.
193
194This is how (Hw)Binder ownership model looks like. The server implementation
195is owned by Binder framework (via sp<>). Proxies are owned by clients.
196When the last proxy disappears, Binder framework releases the server impl.
197
198Thus, it is not needed to keep any references to StreamOutCallback (this is
199the server impl) -- it will live as long as HAL server holds a strong ref to
200IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
201from the destructor of StreamOutHalHidl.
202
203The callback only keeps a weak reference to the stream. The stream is owned
204by AudioFlinger.
205
206*/
207
208struct StreamOutCallback : public IStreamOutCallback {
209 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
210
211 // IStreamOutCallback implementation
212 Return<void> onWriteReady() override {
213 sp<StreamOutHalHidl> stream = mStream.promote();
214 if (stream != 0) {
215 stream->onWriteReady();
216 }
217 return Void();
218 }
219
220 Return<void> onDrainReady() override {
221 sp<StreamOutHalHidl> stream = mStream.promote();
222 if (stream != 0) {
223 stream->onDrainReady();
224 }
225 return Void();
226 }
227
228 Return<void> onError() override {
229 sp<StreamOutHalHidl> stream = mStream.promote();
230 if (stream != 0) {
231 stream->onError();
232 }
233 return Void();
234 }
235
236 private:
237 wp<StreamOutHalHidl> mStream;
238};
239
240} // namespace
241
242StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
Mikhail Naganovc8381902017-01-31 13:56:25 -0800243 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800244}
245
246StreamOutHalHidl::~StreamOutHalHidl() {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800247 if (mStream != 0) {
248 if (mCallback.unsafe_get()) {
249 processReturn("clearCallback", mStream->clearCallback());
250 }
251 processReturn("close", mStream->close());
Mikhail Naganovf558e022016-11-14 17:45:17 -0800252 }
253 mCallback.clear();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800254 if (mEfGroup) {
255 EventFlag::deleteEventFlag(&mEfGroup);
256 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800257}
258
259status_t StreamOutHalHidl::getFrameSize(size_t *size) {
260 if (mStream == 0) return NO_INIT;
261 return processReturn("getFrameSize", mStream->getFrameSize(), size);
262}
263
264status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
265 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800266 if (mWriterClient == gettid() && mCommandMQ) {
267 return callWriterThread(
268 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
269 [&](const WriteStatus& writeStatus) {
270 *latency = writeStatus.reply.latencyMs;
271 });
272 } else {
273 return processReturn("getLatency", mStream->getLatency(), latency);
274 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800275}
276
277status_t StreamOutHalHidl::setVolume(float left, float right) {
278 if (mStream == 0) return NO_INIT;
279 return processReturn("setVolume", mStream->setVolume(left, right));
280}
281
282status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
283 if (mStream == 0) return NO_INIT;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800284 *written = 0;
285
286 if (bytes == 0 && !mDataMQ) {
287 // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
288 ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes");
289 return OK;
290 }
291
292 status_t status;
293 if (!mDataMQ && (status = prepareForWriting(bytes)) != OK) {
294 return status;
295 }
296
Mikhail Naganovc8381902017-01-31 13:56:25 -0800297 return callWriterThread(
298 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
299 [&] (const WriteStatus& writeStatus) {
300 *written = writeStatus.reply.written;
301 });
302}
303
304status_t StreamOutHalHidl::callWriterThread(
305 WriteCommand cmd, const char* cmdName,
306 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
307 if (!mCommandMQ->write(&cmd)) {
308 ALOGE("command message queue write failed for \"%s\"", cmdName);
309 return -EAGAIN;
310 }
311 if (data != nullptr) {
312 size_t availableToWrite = mDataMQ->availableToWrite();
313 if (dataSize > availableToWrite) {
314 ALOGW("truncating write data from %d to %d due to insufficient data queue space",
315 (int32_t)dataSize, (int32_t)availableToWrite);
316 dataSize = availableToWrite;
317 }
318 if (!mDataMQ->write(data, dataSize)) {
319 ALOGE("data message queue write failed for \"%s\"", cmdName);
320 }
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800321 }
322 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
323
324 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
325 uint32_t efState = 0;
326retry:
327 status_t ret = mEfGroup->wait(
328 static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState, NS_PER_SEC);
329 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800330 WriteStatus writeStatus;
331 writeStatus.retval = Result::NOT_INITIALIZED;
332 if (!mStatusMQ->read(&writeStatus)) {
333 ALOGE("status message read failed for \"%s\"", cmdName);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800334 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800335 if (writeStatus.retval == Result::OK) {
336 ret = OK;
337 callback(writeStatus);
338 } else {
339 ret = processReturn(cmdName, writeStatus.retval);
340 }
341 return ret;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800342 }
343 if (ret == -EAGAIN) {
344 // This normally retries no more than once.
345 goto retry;
346 }
347 return ret;
348}
349
350status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800351 std::unique_ptr<CommandMQ> tempCommandMQ;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800352 std::unique_ptr<DataMQ> tempDataMQ;
353 std::unique_ptr<StatusMQ> tempStatusMQ;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800354 Result retval;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800355 Return<void> ret = mStream->prepareForWriting(
356 1, bufferSize, ThreadPriority(mHalThreadPriority),
357 [&](Result r,
Mikhail Naganovc8381902017-01-31 13:56:25 -0800358 const CommandMQ::Descriptor& commandMQ,
Hridya Valsaraju085ae9a2017-01-10 09:42:17 -0800359 const DataMQ::Descriptor& dataMQ,
360 const StatusMQ::Descriptor& statusMQ) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800361 retval = r;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800362 if (retval == Result::OK) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800363 tempCommandMQ.reset(new CommandMQ(commandMQ));
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800364 tempDataMQ.reset(new DataMQ(dataMQ));
365 tempStatusMQ.reset(new StatusMQ(statusMQ));
366 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
367 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
368 }
369 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800370 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800371 if (!ret.isOk() || retval != Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800372 return processReturn("prepareForWriting", ret, retval);
373 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800374 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
375 !tempDataMQ || !tempDataMQ->isValid() ||
376 !tempStatusMQ || !tempStatusMQ->isValid() ||
377 !mEfGroup) {
378 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
379 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
380 "Command message queue for writing is invalid");
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800381 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
382 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
383 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
384 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
385 "Status message queue for writing is invalid");
386 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
387 return NO_INIT;
388 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800389 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800390 mDataMQ = std::move(tempDataMQ);
391 mStatusMQ = std::move(tempStatusMQ);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800392 mWriterClient = gettid();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800393 return OK;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800394}
395
396status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
397 if (mStream == 0) return NO_INIT;
398 Result retval;
399 Return<void> ret = mStream->getRenderPosition(
400 [&](Result r, uint32_t d) {
401 retval = r;
402 if (retval == Result::OK) {
403 *dspFrames = d;
404 }
405 });
406 return processReturn("getRenderPosition", ret, retval);
407}
408
409status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
410 if (mStream == 0) return NO_INIT;
411 Result retval;
412 Return<void> ret = mStream->getNextWriteTimestamp(
413 [&](Result r, int64_t t) {
414 retval = r;
415 if (retval == Result::OK) {
416 *timestamp = t;
417 }
418 });
419 return processReturn("getRenderPosition", ret, retval);
420}
421
422status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
423 if (mStream == 0) return NO_INIT;
424 status_t status = processReturn(
425 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
426 if (status == OK) {
427 mCallback = callback;
428 }
429 return status;
430}
431
432status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
433 if (mStream == 0) return NO_INIT;
434 Return<void> ret = mStream->supportsPauseAndResume(
435 [&](bool p, bool r) {
436 *supportsPause = p;
437 *supportsResume = r;
438 });
439 return processReturn("supportsPauseAndResume", ret);
440}
441
442status_t StreamOutHalHidl::pause() {
443 if (mStream == 0) return NO_INIT;
444 return processReturn("pause", mStream->pause());
445}
446
447status_t StreamOutHalHidl::resume() {
448 if (mStream == 0) return NO_INIT;
449 return processReturn("pause", mStream->resume());
450}
451
452status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
453 if (mStream == 0) return NO_INIT;
454 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
455}
456
457status_t StreamOutHalHidl::drain(bool earlyNotify) {
458 if (mStream == 0) return NO_INIT;
459 return processReturn(
460 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
461}
462
463status_t StreamOutHalHidl::flush() {
464 if (mStream == 0) return NO_INIT;
465 return processReturn("pause", mStream->flush());
466}
467
468status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
469 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800470 if (mWriterClient == gettid() && mCommandMQ) {
471 return callWriterThread(
472 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
473 [&](const WriteStatus& writeStatus) {
474 *frames = writeStatus.reply.presentationPosition.frames;
475 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
476 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
477 });
478 } else {
479 Result retval;
480 Return<void> ret = mStream->getPresentationPosition(
481 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
482 retval = r;
483 if (retval == Result::OK) {
484 *frames = hidlFrames;
485 timestamp->tv_sec = hidlTimeStamp.tvSec;
486 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
487 }
488 });
489 return processReturn("getPresentationPosition", ret, retval);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800490 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800491}
492
493void StreamOutHalHidl::onWriteReady() {
494 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
495 if (callback == 0) return;
496 ALOGV("asyncCallback onWriteReady");
497 callback->onWriteReady();
498}
499
500void StreamOutHalHidl::onDrainReady() {
501 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
502 if (callback == 0) return;
503 ALOGV("asyncCallback onDrainReady");
504 callback->onDrainReady();
505}
506
507void StreamOutHalHidl::onError() {
508 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
509 if (callback == 0) return;
510 ALOGV("asyncCallback onError");
511 callback->onError();
512}
513
514
515StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
Mikhail Naganovc8381902017-01-31 13:56:25 -0800516 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800517}
518
519StreamInHalHidl::~StreamInHalHidl() {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800520 if (mStream != 0) {
521 processReturn("close", mStream->close());
522 }
523 if (mEfGroup) {
524 EventFlag::deleteEventFlag(&mEfGroup);
525 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800526}
527
528status_t StreamInHalHidl::getFrameSize(size_t *size) {
529 if (mStream == 0) return NO_INIT;
530 return processReturn("getFrameSize", mStream->getFrameSize(), size);
531}
532
533status_t StreamInHalHidl::setGain(float gain) {
534 if (mStream == 0) return NO_INIT;
535 return processReturn("setGain", mStream->setGain(gain));
536}
537
538status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
539 if (mStream == 0) return NO_INIT;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800540 *read = 0;
541
542 if (bytes == 0 && !mDataMQ) {
543 // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
544 return OK;
545 }
546
547 status_t status;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800548 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
549 return status;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800550 }
551
Mikhail Naganovc8381902017-01-31 13:56:25 -0800552 ReadParameters params;
553 params.command = ReadCommand::READ;
554 params.params.read = bytes;
555 return callReaderThread(params, "read",
556 [&](const ReadStatus& readStatus) {
557 const size_t availToRead = mDataMQ->availableToRead();
558 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
559 ALOGE("data message queue read failed for \"read\"");
560 }
561 ALOGW_IF(availToRead != readStatus.reply.read,
562 "HAL read report inconsistent: mq = %d, status = %d",
563 (int32_t)availToRead, (int32_t)readStatus.reply.read);
564 *read = readStatus.reply.read;
565 });
566}
567
568status_t StreamInHalHidl::callReaderThread(
569 const ReadParameters& params, const char* cmdName,
570 StreamInHalHidl::ReaderCallback callback) {
571 if (!mCommandMQ->write(&params)) {
572 ALOGW("command message queue write failed");
573 return -EAGAIN;
574 }
575 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
576
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800577 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
578 uint32_t efState = 0;
579retry:
580 status_t ret = mEfGroup->wait(
581 static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState, NS_PER_SEC);
582 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800583 ReadStatus readStatus;
584 readStatus.retval = Result::NOT_INITIALIZED;
585 if (!mStatusMQ->read(&readStatus)) {
586 ALOGE("status message read failed for \"%s\"", cmdName);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800587 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800588 if (readStatus.retval == Result::OK) {
589 ret = OK;
590 callback(readStatus);
591 } else {
592 ret = processReturn(cmdName, readStatus.retval);
593 }
594 return ret;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800595 }
596 if (ret == -EAGAIN) {
597 // This normally retries no more than once.
598 goto retry;
599 }
600 return ret;
601}
602
603status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800604 std::unique_ptr<CommandMQ> tempCommandMQ;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800605 std::unique_ptr<DataMQ> tempDataMQ;
606 std::unique_ptr<StatusMQ> tempStatusMQ;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800607 Result retval;
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800608 Return<void> ret = mStream->prepareForReading(
609 1, bufferSize, ThreadPriority(mHalThreadPriority),
610 [&](Result r,
Mikhail Naganovc8381902017-01-31 13:56:25 -0800611 const CommandMQ::Descriptor& commandMQ,
Hridya Valsaraju085ae9a2017-01-10 09:42:17 -0800612 const DataMQ::Descriptor& dataMQ,
613 const StatusMQ::Descriptor& statusMQ) {
Mikhail Naganovf558e022016-11-14 17:45:17 -0800614 retval = r;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800615 if (retval == Result::OK) {
Mikhail Naganovc8381902017-01-31 13:56:25 -0800616 tempCommandMQ.reset(new CommandMQ(commandMQ));
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800617 tempDataMQ.reset(new DataMQ(dataMQ));
618 tempStatusMQ.reset(new StatusMQ(statusMQ));
619 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
620 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
621 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800622 }
623 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800624 if (!ret.isOk() || retval != Result::OK) {
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800625 return processReturn("prepareForReading", ret, retval);
626 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800627 if (!tempCommandMQ || !tempCommandMQ->isValid() ||
628 !tempDataMQ || !tempDataMQ->isValid() ||
629 !tempStatusMQ || !tempStatusMQ->isValid() ||
630 !mEfGroup) {
631 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
632 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
633 "Command message queue for writing is invalid");
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800634 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
635 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
636 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
637 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
638 "Status message queue for reading is invalid");
639 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
640 return NO_INIT;
641 }
Mikhail Naganovc8381902017-01-31 13:56:25 -0800642 mCommandMQ = std::move(tempCommandMQ);
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800643 mDataMQ = std::move(tempDataMQ);
644 mStatusMQ = std::move(tempStatusMQ);
Mikhail Naganovc8381902017-01-31 13:56:25 -0800645 mReaderClient = gettid();
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800646 return OK;
Mikhail Naganovf558e022016-11-14 17:45:17 -0800647}
648
649status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
650 if (mStream == 0) return NO_INIT;
651 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
652}
653
654status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
655 if (mStream == 0) return NO_INIT;
Mikhail Naganovc8381902017-01-31 13:56:25 -0800656 if (mReaderClient == gettid() && mCommandMQ) {
657 ReadParameters params;
658 params.command = ReadCommand::GET_CAPTURE_POSITION;
659 return callReaderThread(params, "getCapturePosition",
660 [&](const ReadStatus& readStatus) {
661 *frames = readStatus.reply.capturePosition.frames;
662 *time = readStatus.reply.capturePosition.time;
663 });
664 } else {
665 Result retval;
666 Return<void> ret = mStream->getCapturePosition(
667 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
668 retval = r;
669 if (retval == Result::OK) {
670 *frames = hidlFrames;
671 *time = hidlTime;
672 }
673 });
674 return processReturn("getCapturePosition", ret, retval);
675 }
Mikhail Naganovf558e022016-11-14 17:45:17 -0800676}
677
678} // namespace android