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