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