Home | History | Annotate | Download | only in audioflinger
      1 /*
      2  * Copyright (C) 2014 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 "FastCapture"
     18 //#define LOG_NDEBUG 0
     19 
     20 #define ATRACE_TAG ATRACE_TAG_AUDIO
     21 
     22 #include "Configuration.h"
     23 #include <audio_utils/format.h>
     24 #include <linux/futex.h>
     25 #include <sys/syscall.h>
     26 #include <media/AudioBufferProvider.h>
     27 #include <utils/Log.h>
     28 #include <utils/Trace.h>
     29 #include "FastCapture.h"
     30 
     31 namespace android {
     32 
     33 /*static*/ const FastCaptureState FastCapture::sInitial;
     34 
     35 FastCapture::FastCapture() : FastThread("cycleC_ms", "loadC_us"),
     36     mInputSource(NULL), mInputSourceGen(0), mPipeSink(NULL), mPipeSinkGen(0),
     37     mReadBuffer(NULL), mReadBufferState(-1), mFormat(Format_Invalid), mSampleRate(0),
     38     // mDummyDumpState
     39     mTotalNativeFramesRead(0)
     40 {
     41     mPrevious = &sInitial;
     42     mCurrent = &sInitial;
     43 
     44     mDummyDumpState = &mDummyFastCaptureDumpState;
     45 }
     46 
     47 FastCapture::~FastCapture()
     48 {
     49 }
     50 
     51 FastCaptureStateQueue* FastCapture::sq()
     52 {
     53     return &mSQ;
     54 }
     55 
     56 const FastThreadState *FastCapture::poll()
     57 {
     58     return mSQ.poll();
     59 }
     60 
     61 void FastCapture::setNBLogWriter(NBLog::Writer *logWriter __unused)
     62 {
     63 }
     64 
     65 void FastCapture::onIdle()
     66 {
     67     mPreIdle = *(const FastCaptureState *)mCurrent;
     68     mCurrent = &mPreIdle;
     69 }
     70 
     71 void FastCapture::onExit()
     72 {
     73     free(mReadBuffer);
     74 }
     75 
     76 bool FastCapture::isSubClassCommand(FastThreadState::Command command)
     77 {
     78     switch ((FastCaptureState::Command) command) {
     79     case FastCaptureState::READ:
     80     case FastCaptureState::WRITE:
     81     case FastCaptureState::READ_WRITE:
     82         return true;
     83     default:
     84         return false;
     85     }
     86 }
     87 
     88 void FastCapture::onStateChange()
     89 {
     90     const FastCaptureState * const current = (const FastCaptureState *) mCurrent;
     91     const FastCaptureState * const previous = (const FastCaptureState *) mPrevious;
     92     FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) mDumpState;
     93     const size_t frameCount = current->mFrameCount;
     94 
     95     bool eitherChanged = false;
     96 
     97     // check for change in input HAL configuration
     98     NBAIO_Format previousFormat = mFormat;
     99     if (current->mInputSourceGen != mInputSourceGen) {
    100         mInputSource = current->mInputSource;
    101         mInputSourceGen = current->mInputSourceGen;
    102         if (mInputSource == NULL) {
    103             mFormat = Format_Invalid;
    104             mSampleRate = 0;
    105         } else {
    106             mFormat = mInputSource->format();
    107             mSampleRate = Format_sampleRate(mFormat);
    108 #if !LOG_NDEBUG
    109             unsigned channelCount = Format_channelCount(mFormat);
    110             ALOG_ASSERT(channelCount >= 1 && channelCount <= FCC_8);
    111 #endif
    112         }
    113         dumpState->mSampleRate = mSampleRate;
    114         eitherChanged = true;
    115     }
    116 
    117     // check for change in pipe
    118     if (current->mPipeSinkGen != mPipeSinkGen) {
    119         mPipeSink = current->mPipeSink;
    120         mPipeSinkGen = current->mPipeSinkGen;
    121         eitherChanged = true;
    122     }
    123 
    124     // input source and pipe sink must be compatible
    125     if (eitherChanged && mInputSource != NULL && mPipeSink != NULL) {
    126         ALOG_ASSERT(Format_isEqual(mFormat, mPipeSink->format()));
    127     }
    128 
    129     if ((!Format_isEqual(mFormat, previousFormat)) || (frameCount != previous->mFrameCount)) {
    130         // FIXME to avoid priority inversion, don't free here
    131         free(mReadBuffer);
    132         mReadBuffer = NULL;
    133         if (frameCount > 0 && mSampleRate > 0) {
    134             // FIXME new may block for unbounded time at internal mutex of the heap
    135             //       implementation; it would be better to have normal capture thread allocate for
    136             //       us to avoid blocking here and to prevent possible priority inversion
    137             size_t bufferSize = frameCount * Format_frameSize(mFormat);
    138             (void)posix_memalign(&mReadBuffer, 32, bufferSize);
    139             memset(mReadBuffer, 0, bufferSize); // if posix_memalign fails, will segv here.
    140             mPeriodNs = (frameCount * 1000000000LL) / mSampleRate;      // 1.00
    141             mUnderrunNs = (frameCount * 1750000000LL) / mSampleRate;    // 1.75
    142             mOverrunNs = (frameCount * 500000000LL) / mSampleRate;      // 0.50
    143             mForceNs = (frameCount * 950000000LL) / mSampleRate;        // 0.95
    144             mWarmupNsMin = (frameCount * 750000000LL) / mSampleRate;    // 0.75
    145             mWarmupNsMax = (frameCount * 1250000000LL) / mSampleRate;   // 1.25
    146         } else {
    147             mPeriodNs = 0;
    148             mUnderrunNs = 0;
    149             mOverrunNs = 0;
    150             mForceNs = 0;
    151             mWarmupNsMin = 0;
    152             mWarmupNsMax = LONG_MAX;
    153         }
    154         mReadBufferState = -1;
    155         dumpState->mFrameCount = frameCount;
    156     }
    157 
    158 }
    159 
    160 void FastCapture::onWork()
    161 {
    162     const FastCaptureState * const current = (const FastCaptureState *) mCurrent;
    163     FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) mDumpState;
    164     const FastCaptureState::Command command = mCommand;
    165     size_t frameCount = current->mFrameCount;
    166     AudioBufferProvider* fastPatchRecordBufferProvider = current->mFastPatchRecordBufferProvider;
    167     AudioBufferProvider::Buffer patchBuffer;
    168 
    169     if (fastPatchRecordBufferProvider != 0) {
    170         patchBuffer.frameCount = ~0;
    171         status_t status = fastPatchRecordBufferProvider->getNextBuffer(&patchBuffer);
    172         if (status != NO_ERROR) {
    173             frameCount = 0;
    174         } else if (patchBuffer.frameCount < frameCount) {
    175             // TODO: Make sure that it doesn't cause any issues if we just get a small available
    176             // buffer from the buffer provider.
    177             frameCount = patchBuffer.frameCount;
    178         }
    179     }
    180 
    181     if ((command & FastCaptureState::READ) /*&& isWarm*/) {
    182         ALOG_ASSERT(mInputSource != NULL);
    183         ALOG_ASSERT(mReadBuffer != NULL);
    184         dumpState->mReadSequence++;
    185         ATRACE_BEGIN("read");
    186         ssize_t framesRead = mInputSource->read(mReadBuffer, frameCount);
    187         ATRACE_END();
    188         dumpState->mReadSequence++;
    189         if (framesRead >= 0) {
    190             LOG_ALWAYS_FATAL_IF((size_t) framesRead > frameCount);
    191             mTotalNativeFramesRead += framesRead;
    192             dumpState->mFramesRead = mTotalNativeFramesRead;
    193             mReadBufferState = framesRead;
    194             patchBuffer.frameCount = framesRead;
    195         } else {
    196             dumpState->mReadErrors++;
    197             mReadBufferState = 0;
    198         }
    199         // FIXME rename to attemptedIO
    200         mAttemptedWrite = true;
    201     }
    202 
    203     if (command & FastCaptureState::WRITE) {
    204         ALOG_ASSERT(mPipeSink != NULL);
    205         ALOG_ASSERT(mReadBuffer != NULL);
    206         if (mReadBufferState < 0) {
    207             memset(mReadBuffer, 0, frameCount * Format_frameSize(mFormat));
    208             mReadBufferState = frameCount;
    209         }
    210         if (mReadBufferState > 0) {
    211             ssize_t framesWritten = mPipeSink->write(mReadBuffer, mReadBufferState);
    212             audio_track_cblk_t* cblk = current->mCblk;
    213             if (fastPatchRecordBufferProvider != 0) {
    214                 // This indicates the fast track is a patch record, update the cblk by
    215                 // calling releaseBuffer().
    216                 memcpy_by_audio_format(patchBuffer.raw, current->mFastPatchRecordFormat,
    217                         mReadBuffer, mFormat.mFormat, framesWritten * mFormat.mChannelCount);
    218                 patchBuffer.frameCount = framesWritten;
    219                 fastPatchRecordBufferProvider->releaseBuffer(&patchBuffer);
    220             } else if (cblk != NULL && framesWritten > 0) {
    221                 // FIXME This supports at most one fast capture client.
    222                 //       To handle multiple clients this could be converted to an array,
    223                 //       or with a lot more work the control block could be shared by all clients.
    224                 int32_t rear = cblk->u.mStreaming.mRear;
    225                 android_atomic_release_store(framesWritten + rear, &cblk->u.mStreaming.mRear);
    226                 cblk->mServer += framesWritten;
    227                 int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
    228                 if (!(old & CBLK_FUTEX_WAKE)) {
    229                     // client is never in server process, so don't use FUTEX_WAKE_PRIVATE
    230                     (void) syscall(__NR_futex, &cblk->mFutex, FUTEX_WAKE, 1);
    231                 }
    232             }
    233         }
    234     }
    235 }
    236 
    237 }   // namespace android
    238