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