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