Home | History | Annotate | Download | only in 4.0
      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 
     30 using ::android::hardware::audio::common::V4_0::AudioChannelMask;
     31 using ::android::hardware::audio::common::V4_0::AudioContentType;
     32 using ::android::hardware::audio::common::V4_0::AudioFormat;
     33 using ::android::hardware::audio::common::V4_0::AudioSource;
     34 using ::android::hardware::audio::common::V4_0::AudioUsage;
     35 using ::android::hardware::audio::common::V4_0::ThreadInfo;
     36 using ::android::hardware::audio::V4_0::AudioDrain;
     37 using ::android::hardware::audio::V4_0::IStreamOutCallback;
     38 using ::android::hardware::audio::V4_0::MessageQueueFlagBits;
     39 using ::android::hardware::audio::V4_0::MicrophoneInfo;
     40 using ::android::hardware::audio::V4_0::MmapBufferInfo;
     41 using ::android::hardware::audio::V4_0::MmapPosition;
     42 using ::android::hardware::audio::V4_0::ParameterValue;
     43 using ::android::hardware::audio::V4_0::PlaybackTrackMetadata;
     44 using ::android::hardware::audio::V4_0::RecordTrackMetadata;
     45 using ::android::hardware::audio::V4_0::Result;
     46 using ::android::hardware::audio::V4_0::TimeSpec;
     47 using ::android::hardware::MQDescriptorSync;
     48 using ::android::hardware::Return;
     49 using ::android::hardware::Void;
     50 using ReadCommand = ::android::hardware::audio::V4_0::IStreamIn::ReadCommand;
     51 
     52 namespace android {
     53 namespace V4_0 {
     54 
     55 StreamHalHidl::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 
     74 StreamHalHidl::~StreamHalHidl() {
     75     mStream = nullptr;
     76 }
     77 
     78 status_t StreamHalHidl::getSampleRate(uint32_t *rate) {
     79     if (!mStream) return NO_INIT;
     80     return processReturn("getSampleRate", mStream->getSampleRate(), rate);
     81 }
     82 
     83 status_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 
     92 status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) {
     93     if (!mStream) return NO_INIT;
     94     return processReturn("getChannelMask", mStream->getChannelMask(), mask);
     95 }
     96 
     97 status_t StreamHalHidl::getFormat(audio_format_t *format) {
     98     if (!mStream) return NO_INIT;
     99     return processReturn("getFormat", mStream->getFormat(), format);
    100 }
    101 
    102 status_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 
    114 status_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 
    123 status_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 
    143 status_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 
    149 status_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 
    155 status_t StreamHalHidl::standby() {
    156     if (!mStream) return NO_INIT;
    157     return processReturn("standby", mStream->standby());
    158 }
    159 
    160 status_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 
    170 status_t StreamHalHidl::start() {
    171     if (!mStream) return NO_INIT;
    172     return processReturn("start", mStream->start());
    173 }
    174 
    175 status_t StreamHalHidl::stop() {
    176     if (!mStream) return NO_INIT;
    177     return processReturn("stop", mStream->stop());
    178 }
    179 
    180 status_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 
    203 status_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 
    216 status_t StreamHalHidl::setHalThreadPriority(int priority) {
    217     mHalThreadPriority = priority;
    218     return OK;
    219 }
    220 
    221 status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
    222     if (mCachedBufferSize != 0) {
    223         *size = mCachedBufferSize;
    224         return OK;
    225     }
    226     return getBufferSize(size);
    227 }
    228 
    229 bool 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 
    242 namespace {
    243 
    244 /* Notes on callback ownership.
    245 
    246 This is how (Hw)Binder ownership model looks like. The server implementation
    247 is owned by Binder framework (via sp<>). Proxies are owned by clients.
    248 When the last proxy disappears, Binder framework releases the server impl.
    249 
    250 Thus, it is not needed to keep any references to StreamOutCallback (this is
    251 the server impl) -- it will live as long as HAL server holds a strong ref to
    252 IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
    253 from the destructor of StreamOutHalHidl.
    254 
    255 The callback only keeps a weak reference to the stream. The stream is owned
    256 by AudioFlinger.
    257 
    258 */
    259 
    260 struct 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 
    294 StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
    295         : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
    296 }
    297 
    298 StreamOutHalHidl::~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 
    313 status_t StreamOutHalHidl::getFrameSize(size_t *size) {
    314     if (mStream == 0) return NO_INIT;
    315     return processReturn("getFrameSize", mStream->getFrameSize(), size);
    316 }
    317 
    318 status_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 
    331 status_t StreamOutHalHidl::setVolume(float left, float right) {
    332     if (mStream == 0) return NO_INIT;
    333     return processReturn("setVolume", mStream->setVolume(left, right));
    334 }
    335 
    336 status_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 
    375 status_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;
    397 retry:
    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 
    420 status_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 
    472 status_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 
    485 status_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 
    498 status_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 
    508 status_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 
    518 status_t StreamOutHalHidl::pause() {
    519     if (mStream == 0) return NO_INIT;
    520     return processReturn("pause", mStream->pause());
    521 }
    522 
    523 status_t StreamOutHalHidl::resume() {
    524     if (mStream == 0) return NO_INIT;
    525     return processReturn("pause", mStream->resume());
    526 }
    527 
    528 status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
    529     if (mStream == 0) return NO_INIT;
    530     return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
    531 }
    532 
    533 status_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 
    539 status_t StreamOutHalHidl::flush() {
    540     if (mStream == 0) return NO_INIT;
    541     return processReturn("pause", mStream->flush());
    542 }
    543 
    544 status_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. */
    570 template <class Values, class ElementConverter>
    571 static 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 
    578 status_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 
    591 void StreamOutHalHidl::onWriteReady() {
    592     sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
    593     if (callback == 0) return;
    594     ALOGV("asyncCallback onWriteReady");
    595     callback->onWriteReady();
    596 }
    597 
    598 void StreamOutHalHidl::onDrainReady() {
    599     sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
    600     if (callback == 0) return;
    601     ALOGV("asyncCallback onDrainReady");
    602     callback->onDrainReady();
    603 }
    604 
    605 void StreamOutHalHidl::onError() {
    606     sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
    607     if (callback == 0) return;
    608     ALOGV("asyncCallback onError");
    609     callback->onError();
    610 }
    611 
    612 
    613 StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
    614         : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
    615 }
    616 
    617 StreamInHalHidl::~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 
    628 status_t StreamInHalHidl::getFrameSize(size_t *size) {
    629     if (mStream == 0) return NO_INIT;
    630     return processReturn("getFrameSize", mStream->getFrameSize(), size);
    631 }
    632 
    633 status_t StreamInHalHidl::setGain(float gain) {
    634     if (mStream == 0) return NO_INIT;
    635     return processReturn("setGain", mStream->setGain(gain));
    636 }
    637 
    638 status_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 
    670 status_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;
    681 retry:
    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 
    704 status_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 
    756 status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
    757     if (mStream == 0) return NO_INIT;
    758     return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
    759 }
    760 
    761 status_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 
    786 status_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 
    804 status_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