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