• 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 <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::sInitial;
33 
FastCapture()34 FastCapture::FastCapture() : FastThread("cycleC_ms", "loadC_us"),
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 
~FastCapture()46 FastCapture::~FastCapture()
47 {
48 }
49 
sq()50 FastCaptureStateQueue* FastCapture::sq()
51 {
52     return &mSQ;
53 }
54 
poll()55 const FastThreadState *FastCapture::poll()
56 {
57     return mSQ.poll();
58 }
59 
setNBLogWriter(NBLog::Writer * logWriter __unused)60 void FastCapture::setNBLogWriter(NBLog::Writer *logWriter __unused)
61 {
62 }
63 
onIdle()64 void FastCapture::onIdle()
65 {
66     mPreIdle = *(const FastCaptureState *)mCurrent;
67     mCurrent = &mPreIdle;
68 }
69 
onExit()70 void FastCapture::onExit()
71 {
72     free(mReadBuffer);
73 }
74 
isSubClassCommand(FastThreadState::Command command)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 
onStateChange()87 void 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 
onWork()159 void 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