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::initial;
     33 
     34 FastCapture::FastCapture() : FastThread(),
     35     inputSource(NULL), inputSourceGen(0), pipeSink(NULL), pipeSinkGen(0),
     36     readBuffer(NULL), readBufferState(-1), format(Format_Invalid), sampleRate(0),
     37     // dummyDumpState
     38     totalNativeFramesRead(0)
     39 {
     40     previous = &initial;
     41     current = &initial;
     42 
     43     mDummyDumpState = &dummyDumpState;
     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::setLog(NBLog::Writer *logWriter __unused)
     61 {
     62 }
     63 
     64 void FastCapture::onIdle()
     65 {
     66     preIdle = *(const FastCaptureState *)current;
     67     current = &preIdle;
     68 }
     69 
     70 void FastCapture::onExit()
     71 {
     72     delete[] readBuffer;
     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 *) this->current;
     90     const FastCaptureState * const previous = (const FastCaptureState *) this->previous;
     91     FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) this->dumpState;
     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 = format;
     98     if (current->mInputSourceGen != inputSourceGen) {
     99         inputSource = current->mInputSource;
    100         inputSourceGen = current->mInputSourceGen;
    101         if (inputSource == NULL) {
    102             format = Format_Invalid;
    103             sampleRate = 0;
    104         } else {
    105             format = inputSource->format();
    106             sampleRate = Format_sampleRate(format);
    107             unsigned channelCount = Format_channelCount(format);
    108             ALOG_ASSERT(channelCount == 1 || channelCount == 2);
    109         }
    110         dumpState->mSampleRate = sampleRate;
    111         eitherChanged = true;
    112     }
    113 
    114     // check for change in pipe
    115     if (current->mPipeSinkGen != pipeSinkGen) {
    116         pipeSink = current->mPipeSink;
    117         pipeSinkGen = current->mPipeSinkGen;
    118         eitherChanged = true;
    119     }
    120 
    121     // input source and pipe sink must be compatible
    122     if (eitherChanged && inputSource != NULL && pipeSink != NULL) {
    123         ALOG_ASSERT(Format_isEqual(format, pipeSink->format()));
    124     }
    125 
    126     if ((!Format_isEqual(format, previousFormat)) || (frameCount != previous->mFrameCount)) {
    127         // FIXME to avoid priority inversion, don't delete here
    128         delete[] readBuffer;
    129         readBuffer = NULL;
    130         if (frameCount > 0 && sampleRate > 0) {
    131             // FIXME new may block for unbounded time at internal mutex of the heap
    132             //       implementation; it would be better to have normal capture thread allocate for
    133             //       us to avoid blocking here and to prevent possible priority inversion
    134             unsigned channelCount = Format_channelCount(format);
    135             // FIXME frameSize
    136             readBuffer = new short[frameCount * channelCount];
    137             periodNs = (frameCount * 1000000000LL) / sampleRate;    // 1.00
    138             underrunNs = (frameCount * 1750000000LL) / sampleRate;  // 1.75
    139             overrunNs = (frameCount * 500000000LL) / sampleRate;    // 0.50
    140             forceNs = (frameCount * 950000000LL) / sampleRate;      // 0.95
    141             warmupNs = (frameCount * 500000000LL) / sampleRate;     // 0.50
    142         } else {
    143             periodNs = 0;
    144             underrunNs = 0;
    145             overrunNs = 0;
    146             forceNs = 0;
    147             warmupNs = 0;
    148         }
    149         readBufferState = -1;
    150         dumpState->mFrameCount = frameCount;
    151     }
    152 
    153 }
    154 
    155 void FastCapture::onWork()
    156 {
    157     const FastCaptureState * const current = (const FastCaptureState *) this->current;
    158     FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) this->dumpState;
    159     const FastCaptureState::Command command = this->command;
    160     const size_t frameCount = current->mFrameCount;
    161 
    162     if ((command & FastCaptureState::READ) /*&& isWarm*/) {
    163         ALOG_ASSERT(inputSource != NULL);
    164         ALOG_ASSERT(readBuffer != NULL);
    165         dumpState->mReadSequence++;
    166         ATRACE_BEGIN("read");
    167         ssize_t framesRead = inputSource->read(readBuffer, frameCount,
    168                 AudioBufferProvider::kInvalidPTS);
    169         ATRACE_END();
    170         dumpState->mReadSequence++;
    171         if (framesRead >= 0) {
    172             LOG_ALWAYS_FATAL_IF((size_t) framesRead > frameCount);
    173             totalNativeFramesRead += framesRead;
    174             dumpState->mFramesRead = totalNativeFramesRead;
    175             readBufferState = framesRead;
    176         } else {
    177             dumpState->mReadErrors++;
    178             readBufferState = 0;
    179         }
    180         // FIXME rename to attemptedIO
    181         attemptedWrite = true;
    182     }
    183 
    184     if (command & FastCaptureState::WRITE) {
    185         ALOG_ASSERT(pipeSink != NULL);
    186         ALOG_ASSERT(readBuffer != NULL);
    187         if (readBufferState < 0) {
    188             unsigned channelCount = Format_channelCount(format);
    189             // FIXME frameSize
    190             memset(readBuffer, 0, frameCount * channelCount * sizeof(short));
    191             readBufferState = frameCount;
    192         }
    193         if (readBufferState > 0) {
    194             ssize_t framesWritten = pipeSink->write(readBuffer, readBufferState);
    195             // FIXME This supports at most one fast capture client.
    196             //       To handle multiple clients this could be converted to an array,
    197             //       or with a lot more work the control block could be shared by all clients.
    198             audio_track_cblk_t* cblk = current->mCblk;
    199             if (cblk != NULL && framesWritten > 0) {
    200                 int32_t rear = cblk->u.mStreaming.mRear;
    201                 android_atomic_release_store(framesWritten + rear, &cblk->u.mStreaming.mRear);
    202                 cblk->mServer += framesWritten;
    203                 int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
    204                 if (!(old & CBLK_FUTEX_WAKE)) {
    205                     // client is never in server process, so don't use FUTEX_WAKE_PRIVATE
    206                     (void) syscall(__NR_futex, &cblk->mFutex, FUTEX_WAKE, 1);
    207                 }
    208             }
    209         }
    210     }
    211 }
    212 
    213 FastCaptureDumpState::FastCaptureDumpState() : FastThreadDumpState(),
    214     mReadSequence(0), mFramesRead(0), mReadErrors(0), mSampleRate(0), mFrameCount(0)
    215 {
    216 }
    217 
    218 FastCaptureDumpState::~FastCaptureDumpState()
    219 {
    220 }
    221 
    222 }   // namespace android
    223