• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
FastCapture()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 
~FastCapture()47 FastCapture::~FastCapture()
48 {
49 }
50 
sq()51 FastCaptureStateQueue* FastCapture::sq()
52 {
53     return &mSQ;
54 }
55 
poll()56 const FastThreadState *FastCapture::poll()
57 {
58     return mSQ.poll();
59 }
60 
setNBLogWriter(NBLog::Writer * logWriter __unused)61 void FastCapture::setNBLogWriter(NBLog::Writer *logWriter __unused)
62 {
63 }
64 
onIdle()65 void FastCapture::onIdle()
66 {
67     mPreIdle = *(const FastCaptureState *)mCurrent;
68     mCurrent = &mPreIdle;
69 }
70 
onExit()71 void FastCapture::onExit()
72 {
73     free(mReadBuffer);
74 }
75 
isSubClassCommand(FastThreadState::Command command)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 
onStateChange()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_LIMIT);
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     dumpState->mSilenced = current->mSilenceCapture;
158 }
159 
onWork()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             if (current->mSilenceCapture) {
212                 memset(mReadBuffer, 0, mReadBufferState * Format_frameSize(mFormat));
213             }
214             ssize_t framesWritten = mPipeSink->write(mReadBuffer, mReadBufferState);
215             audio_track_cblk_t* cblk = current->mCblk;
216             if (fastPatchRecordBufferProvider != 0) {
217                 // This indicates the fast track is a patch record, update the cblk by
218                 // calling releaseBuffer().
219                 memcpy_by_audio_format(patchBuffer.raw, current->mFastPatchRecordFormat,
220                         mReadBuffer, mFormat.mFormat, framesWritten * mFormat.mChannelCount);
221                 patchBuffer.frameCount = framesWritten;
222                 fastPatchRecordBufferProvider->releaseBuffer(&patchBuffer);
223             } else if (cblk != NULL && framesWritten > 0) {
224                 // FIXME This supports at most one fast capture client.
225                 //       To handle multiple clients this could be converted to an array,
226                 //       or with a lot more work the control block could be shared by all clients.
227                 int32_t rear = cblk->u.mStreaming.mRear;
228                 android_atomic_release_store(framesWritten + rear, &cblk->u.mStreaming.mRear);
229                 cblk->mServer += framesWritten;
230                 int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
231                 if (!(old & CBLK_FUTEX_WAKE)) {
232                     // client is never in server process, so don't use FUTEX_WAKE_PRIVATE
233                     (void) syscall(__NR_futex, &cblk->mFutex, FUTEX_WAKE, 1);
234                 }
235             }
236         }
237     }
238 }
239 
240 }   // namespace android
241