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 30namespace android { 31 32/*static*/ const FastCaptureState FastCapture::sInitial; 33 34FastCapture::FastCapture() : FastThread(), 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 46FastCapture::~FastCapture() 47{ 48} 49 50FastCaptureStateQueue* FastCapture::sq() 51{ 52 return &mSQ; 53} 54 55const FastThreadState *FastCapture::poll() 56{ 57 return mSQ.poll(); 58} 59 60void FastCapture::setLog(NBLog::Writer *logWriter __unused) 61{ 62} 63 64void FastCapture::onIdle() 65{ 66 mPreIdle = *(const FastCaptureState *)mCurrent; 67 mCurrent = &mPreIdle; 68} 69 70void FastCapture::onExit() 71{ 72 free(mReadBuffer); 73} 74 75bool 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 87void 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 159void 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