Home | History | Annotate | Download | only in default
      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 "StreamInHAL"
     18 //#define LOG_NDEBUG 0
     19 #define ATRACE_TAG ATRACE_TAG_AUDIO
     20 
     21 #include <android/log.h>
     22 #include <hardware/audio.h>
     23 #include <utils/Trace.h>
     24 #include <memory>
     25 
     26 #include "StreamIn.h"
     27 #include "Util.h"
     28 
     29 using ::android::hardware::audio::V2_0::MessageQueueFlagBits;
     30 
     31 namespace android {
     32 namespace hardware {
     33 namespace audio {
     34 namespace V2_0 {
     35 namespace implementation {
     36 
     37 using ::android::hardware::audio::common::V2_0::ThreadInfo;
     38 
     39 namespace {
     40 
     41 class ReadThread : public Thread {
     42    public:
     43     // ReadThread's lifespan never exceeds StreamIn's lifespan.
     44     ReadThread(std::atomic<bool>* stop, audio_stream_in_t* stream,
     45                StreamIn::CommandMQ* commandMQ, StreamIn::DataMQ* dataMQ,
     46                StreamIn::StatusMQ* statusMQ, EventFlag* efGroup)
     47         : Thread(false /*canCallJava*/),
     48           mStop(stop),
     49           mStream(stream),
     50           mCommandMQ(commandMQ),
     51           mDataMQ(dataMQ),
     52           mStatusMQ(statusMQ),
     53           mEfGroup(efGroup),
     54           mBuffer(nullptr) {}
     55     bool init() {
     56         mBuffer.reset(new (std::nothrow) uint8_t[mDataMQ->getQuantumCount()]);
     57         return mBuffer != nullptr;
     58     }
     59     virtual ~ReadThread() {}
     60 
     61    private:
     62     std::atomic<bool>* mStop;
     63     audio_stream_in_t* mStream;
     64     StreamIn::CommandMQ* mCommandMQ;
     65     StreamIn::DataMQ* mDataMQ;
     66     StreamIn::StatusMQ* mStatusMQ;
     67     EventFlag* mEfGroup;
     68     std::unique_ptr<uint8_t[]> mBuffer;
     69     IStreamIn::ReadParameters mParameters;
     70     IStreamIn::ReadStatus mStatus;
     71 
     72     bool threadLoop() override;
     73 
     74     void doGetCapturePosition();
     75     void doRead();
     76 };
     77 
     78 void ReadThread::doRead() {
     79     size_t availableToWrite = mDataMQ->availableToWrite();
     80     size_t requestedToRead = mParameters.params.read;
     81     if (requestedToRead > availableToWrite) {
     82         ALOGW(
     83             "truncating read data from %d to %d due to insufficient data queue "
     84             "space",
     85             (int32_t)requestedToRead, (int32_t)availableToWrite);
     86         requestedToRead = availableToWrite;
     87     }
     88     ssize_t readResult = mStream->read(mStream, &mBuffer[0], requestedToRead);
     89     mStatus.retval = Result::OK;
     90     uint64_t read = 0;
     91     if (readResult >= 0) {
     92         mStatus.reply.read = readResult;
     93         if (!mDataMQ->write(&mBuffer[0], readResult)) {
     94             ALOGW("data message queue write failed");
     95         }
     96     } else {
     97         mStatus.retval = Stream::analyzeStatus("read", readResult);
     98     }
     99 }
    100 
    101 void ReadThread::doGetCapturePosition() {
    102     mStatus.retval = StreamIn::getCapturePositionImpl(
    103         mStream, &mStatus.reply.capturePosition.frames,
    104         &mStatus.reply.capturePosition.time);
    105 }
    106 
    107 bool ReadThread::threadLoop() {
    108     // This implementation doesn't return control back to the Thread until it
    109     // decides to stop,
    110     // as the Thread uses mutexes, and this can lead to priority inversion.
    111     while (!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
    112         uint32_t efState = 0;
    113         mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL),
    114                        &efState);
    115         if (!(efState &
    116               static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL))) {
    117             continue;  // Nothing to do.
    118         }
    119         if (!mCommandMQ->read(&mParameters)) {
    120             continue;  // Nothing to do.
    121         }
    122         mStatus.replyTo = mParameters.command;
    123         switch (mParameters.command) {
    124             case IStreamIn::ReadCommand::READ:
    125                 doRead();
    126                 break;
    127             case IStreamIn::ReadCommand::GET_CAPTURE_POSITION:
    128                 doGetCapturePosition();
    129                 break;
    130             default:
    131                 ALOGE("Unknown read thread command code %d",
    132                       mParameters.command);
    133                 mStatus.retval = Result::NOT_SUPPORTED;
    134                 break;
    135         }
    136         if (!mStatusMQ->write(&mStatus)) {
    137             ALOGW("status message queue write failed");
    138         }
    139         mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
    140     }
    141 
    142     return false;
    143 }
    144 
    145 }  // namespace
    146 
    147 StreamIn::StreamIn(const sp<Device>& device, audio_stream_in_t* stream)
    148     : mIsClosed(false),
    149       mDevice(device),
    150       mStream(stream),
    151       mStreamCommon(new Stream(&stream->common)),
    152       mStreamMmap(new StreamMmap<audio_stream_in_t>(stream)),
    153       mEfGroup(nullptr),
    154       mStopReadThread(false) {}
    155 
    156 StreamIn::~StreamIn() {
    157     ATRACE_CALL();
    158     close();
    159     if (mReadThread.get()) {
    160         ATRACE_NAME("mReadThread->join");
    161         status_t status = mReadThread->join();
    162         ALOGE_IF(status, "read thread exit error: %s", strerror(-status));
    163     }
    164     if (mEfGroup) {
    165         status_t status = EventFlag::deleteEventFlag(&mEfGroup);
    166         ALOGE_IF(status, "read MQ event flag deletion error: %s",
    167                  strerror(-status));
    168     }
    169     mDevice->closeInputStream(mStream);
    170     mStream = nullptr;
    171 }
    172 
    173 // Methods from ::android::hardware::audio::V2_0::IStream follow.
    174 Return<uint64_t> StreamIn::getFrameSize() {
    175     return audio_stream_in_frame_size(mStream);
    176 }
    177 
    178 Return<uint64_t> StreamIn::getFrameCount() {
    179     return mStreamCommon->getFrameCount();
    180 }
    181 
    182 Return<uint64_t> StreamIn::getBufferSize() {
    183     return mStreamCommon->getBufferSize();
    184 }
    185 
    186 Return<uint32_t> StreamIn::getSampleRate() {
    187     return mStreamCommon->getSampleRate();
    188 }
    189 
    190 Return<void> StreamIn::getSupportedSampleRates(
    191     getSupportedSampleRates_cb _hidl_cb) {
    192     return mStreamCommon->getSupportedSampleRates(_hidl_cb);
    193 }
    194 
    195 Return<Result> StreamIn::setSampleRate(uint32_t sampleRateHz) {
    196     return mStreamCommon->setSampleRate(sampleRateHz);
    197 }
    198 
    199 Return<AudioChannelMask> StreamIn::getChannelMask() {
    200     return mStreamCommon->getChannelMask();
    201 }
    202 
    203 Return<void> StreamIn::getSupportedChannelMasks(
    204     getSupportedChannelMasks_cb _hidl_cb) {
    205     return mStreamCommon->getSupportedChannelMasks(_hidl_cb);
    206 }
    207 
    208 Return<Result> StreamIn::setChannelMask(AudioChannelMask mask) {
    209     return mStreamCommon->setChannelMask(mask);
    210 }
    211 
    212 Return<AudioFormat> StreamIn::getFormat() {
    213     return mStreamCommon->getFormat();
    214 }
    215 
    216 Return<void> StreamIn::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
    217     return mStreamCommon->getSupportedFormats(_hidl_cb);
    218 }
    219 
    220 Return<Result> StreamIn::setFormat(AudioFormat format) {
    221     return mStreamCommon->setFormat(format);
    222 }
    223 
    224 Return<void> StreamIn::getAudioProperties(getAudioProperties_cb _hidl_cb) {
    225     return mStreamCommon->getAudioProperties(_hidl_cb);
    226 }
    227 
    228 Return<Result> StreamIn::addEffect(uint64_t effectId) {
    229     return mStreamCommon->addEffect(effectId);
    230 }
    231 
    232 Return<Result> StreamIn::removeEffect(uint64_t effectId) {
    233     return mStreamCommon->removeEffect(effectId);
    234 }
    235 
    236 Return<Result> StreamIn::standby() {
    237     return mStreamCommon->standby();
    238 }
    239 
    240 Return<AudioDevice> StreamIn::getDevice() {
    241     return mStreamCommon->getDevice();
    242 }
    243 
    244 Return<Result> StreamIn::setDevice(const DeviceAddress& address) {
    245     return mStreamCommon->setDevice(address);
    246 }
    247 
    248 Return<Result> StreamIn::setConnectedState(const DeviceAddress& address,
    249                                            bool connected) {
    250     return mStreamCommon->setConnectedState(address, connected);
    251 }
    252 
    253 Return<Result> StreamIn::setHwAvSync(uint32_t hwAvSync) {
    254     return mStreamCommon->setHwAvSync(hwAvSync);
    255 }
    256 
    257 Return<void> StreamIn::getParameters(const hidl_vec<hidl_string>& keys,
    258                                      getParameters_cb _hidl_cb) {
    259     return mStreamCommon->getParameters(keys, _hidl_cb);
    260 }
    261 
    262 Return<Result> StreamIn::setParameters(
    263     const hidl_vec<ParameterValue>& parameters) {
    264     return mStreamCommon->setParameters(parameters);
    265 }
    266 
    267 Return<void> StreamIn::debugDump(const hidl_handle& fd) {
    268     return mStreamCommon->debugDump(fd);
    269 }
    270 
    271 Return<Result> StreamIn::start() {
    272     return mStreamMmap->start();
    273 }
    274 
    275 Return<Result> StreamIn::stop() {
    276     return mStreamMmap->stop();
    277 }
    278 
    279 Return<void> StreamIn::createMmapBuffer(int32_t minSizeFrames,
    280                                         createMmapBuffer_cb _hidl_cb) {
    281     return mStreamMmap->createMmapBuffer(
    282         minSizeFrames, audio_stream_in_frame_size(mStream), _hidl_cb);
    283 }
    284 
    285 Return<void> StreamIn::getMmapPosition(getMmapPosition_cb _hidl_cb) {
    286     return mStreamMmap->getMmapPosition(_hidl_cb);
    287 }
    288 
    289 Return<Result> StreamIn::close() {
    290     if (mIsClosed) return Result::INVALID_STATE;
    291     mIsClosed = true;
    292     if (mReadThread.get()) {
    293         mStopReadThread.store(true, std::memory_order_release);
    294     }
    295     if (mEfGroup) {
    296         mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
    297     }
    298     return Result::OK;
    299 }
    300 
    301 // Methods from ::android::hardware::audio::V2_0::IStreamIn follow.
    302 Return<void> StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) {
    303     int halSource;
    304     Result retval =
    305         mStreamCommon->getParam(AudioParameter::keyInputSource, &halSource);
    306     AudioSource source(AudioSource::DEFAULT);
    307     if (retval == Result::OK) {
    308         source = AudioSource(halSource);
    309     }
    310     _hidl_cb(retval, source);
    311     return Void();
    312 }
    313 
    314 Return<Result> StreamIn::setGain(float gain) {
    315     if (!isGainNormalized(gain)) {
    316         ALOGW("Can not set a stream input gain (%f) outside [0,1]", gain);
    317         return Result::INVALID_ARGUMENTS;
    318     }
    319     return Stream::analyzeStatus("set_gain", mStream->set_gain(mStream, gain));
    320 }
    321 
    322 Return<void> StreamIn::prepareForReading(uint32_t frameSize,
    323                                          uint32_t framesCount,
    324                                          prepareForReading_cb _hidl_cb) {
    325     status_t status;
    326     ThreadInfo threadInfo = {0, 0};
    327 
    328     // Wrap the _hidl_cb to return an error
    329     auto sendError = [this, &threadInfo, &_hidl_cb](Result result) {
    330         _hidl_cb(result, CommandMQ::Descriptor(), DataMQ::Descriptor(),
    331                  StatusMQ::Descriptor(), threadInfo);
    332 
    333     };
    334 
    335     // Create message queues.
    336     if (mDataMQ) {
    337         ALOGE("the client attempts to call prepareForReading twice");
    338         sendError(Result::INVALID_STATE);
    339         return Void();
    340     }
    341     std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1));
    342 
    343     // Check frameSize and framesCount
    344     if (frameSize == 0 || framesCount == 0) {
    345         ALOGE("Null frameSize (%u) or framesCount (%u)", frameSize,
    346               framesCount);
    347         sendError(Result::INVALID_ARGUMENTS);
    348         return Void();
    349     }
    350 
    351     if (frameSize > Stream::MAX_BUFFER_SIZE / framesCount) {
    352         ALOGE("Buffer too big: %u*%u bytes > MAX_BUFFER_SIZE (%u)", frameSize, framesCount,
    353               Stream::MAX_BUFFER_SIZE);
    354         sendError(Result::INVALID_ARGUMENTS);
    355         return Void();
    356     }
    357     std::unique_ptr<DataMQ> tempDataMQ(
    358         new DataMQ(frameSize * framesCount, true /* EventFlag */));
    359 
    360     std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1));
    361     if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() ||
    362         !tempStatusMQ->isValid()) {
    363         ALOGE_IF(!tempCommandMQ->isValid(), "command MQ is invalid");
    364         ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid");
    365         ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
    366         sendError(Result::INVALID_ARGUMENTS);
    367         return Void();
    368     }
    369     EventFlag* tempRawEfGroup{};
    370     status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(),
    371                                         &tempRawEfGroup);
    372     std::unique_ptr<EventFlag, void (*)(EventFlag*)> tempElfGroup(
    373         tempRawEfGroup, [](auto* ef) { EventFlag::deleteEventFlag(&ef); });
    374     if (status != OK || !tempElfGroup) {
    375         ALOGE("failed creating event flag for data MQ: %s", strerror(-status));
    376         sendError(Result::INVALID_ARGUMENTS);
    377         return Void();
    378     }
    379 
    380     // Create and launch the thread.
    381     auto tempReadThread = std::make_unique<ReadThread>(
    382         &mStopReadThread, mStream, tempCommandMQ.get(), tempDataMQ.get(),
    383         tempStatusMQ.get(), tempElfGroup.get());
    384     if (!tempReadThread->init()) {
    385         ALOGW("failed to start reader thread: %s", strerror(-status));
    386         sendError(Result::INVALID_ARGUMENTS);
    387         return Void();
    388     }
    389     status = tempReadThread->run("reader", PRIORITY_URGENT_AUDIO);
    390     if (status != OK) {
    391         ALOGW("failed to start reader thread: %s", strerror(-status));
    392         sendError(Result::INVALID_ARGUMENTS);
    393         return Void();
    394     }
    395 
    396     mCommandMQ = std::move(tempCommandMQ);
    397     mDataMQ = std::move(tempDataMQ);
    398     mStatusMQ = std::move(tempStatusMQ);
    399     mReadThread = tempReadThread.release();
    400     mEfGroup = tempElfGroup.release();
    401     threadInfo.pid = getpid();
    402     threadInfo.tid = mReadThread->getTid();
    403     _hidl_cb(Result::OK, *mCommandMQ->getDesc(), *mDataMQ->getDesc(),
    404              *mStatusMQ->getDesc(), threadInfo);
    405     return Void();
    406 }
    407 
    408 Return<uint32_t> StreamIn::getInputFramesLost() {
    409     return mStream->get_input_frames_lost(mStream);
    410 }
    411 
    412 // static
    413 Result StreamIn::getCapturePositionImpl(audio_stream_in_t* stream,
    414                                         uint64_t* frames, uint64_t* time) {
    415     // HAL may have a stub function, always returning ENOSYS, don't
    416     // spam the log in this case.
    417     static const std::vector<int> ignoredErrors{ENOSYS};
    418     Result retval(Result::NOT_SUPPORTED);
    419     if (stream->get_capture_position != NULL) return retval;
    420     int64_t halFrames, halTime;
    421     retval = Stream::analyzeStatus("get_capture_position",
    422                                    stream->get_capture_position(stream, &halFrames, &halTime),
    423                                    ignoredErrors);
    424     if (retval == Result::OK) {
    425         *frames = halFrames;
    426         *time = halTime;
    427     }
    428     return retval;
    429 };
    430 
    431 Return<void> StreamIn::getCapturePosition(getCapturePosition_cb _hidl_cb) {
    432     uint64_t frames = 0, time = 0;
    433     Result retval = getCapturePositionImpl(mStream, &frames, &time);
    434     _hidl_cb(retval, frames, time);
    435     return Void();
    436 }
    437 
    438 }  // namespace implementation
    439 }  // namespace V2_0
    440 }  // namespace audio
    441 }  // namespace hardware
    442 }  // namespace android
    443