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