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 {
37     // base class initialization
38     mPrevious = &sInitial;
39     mCurrent = &sInitial;
40     mDummyDumpState = &mDummyFastCaptureDumpState;
41 }
42 
sq()43 FastCaptureStateQueue* FastCapture::sq()
44 {
45     return &mSQ;
46 }
47 
poll()48 const FastThreadState *FastCapture::poll()
49 {
50     return mSQ.poll();
51 }
52 
setNBLogWriter(NBLog::Writer * logWriter __unused)53 void FastCapture::setNBLogWriter(NBLog::Writer *logWriter __unused)
54 {
55 }
56 
onIdle()57 void FastCapture::onIdle()
58 {
59     mPreIdle = *(const FastCaptureState *)mCurrent;
60     mCurrent = &mPreIdle;
61 }
62 
onExit()63 void FastCapture::onExit()
64 {
65     free(mReadBuffer);
66 }
67 
isSubClassCommand(FastThreadState::Command command)68 bool FastCapture::isSubClassCommand(FastThreadState::Command command)
69 {
70     switch ((FastCaptureState::Command) command) {
71     case FastCaptureState::READ:
72     case FastCaptureState::WRITE:
73     case FastCaptureState::READ_WRITE:
74         return true;
75     default:
76         return false;
77     }
78 }
79 
onStateChange()80 void FastCapture::onStateChange()
81 {
82     const FastCaptureState * const current = (const FastCaptureState *) mCurrent;
83     const FastCaptureState * const previous = (const FastCaptureState *) mPrevious;
84     FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) mDumpState;
85     const size_t frameCount = current->mFrameCount;
86 
87     bool eitherChanged = false;
88 
89     // check for change in input HAL configuration
90     const NBAIO_Format previousFormat = mFormat;
91     if (current->mInputSourceGen != mInputSourceGen) {
92         mInputSource = current->mInputSource;
93         mInputSourceGen = current->mInputSourceGen;
94         if (mInputSource == nullptr) {
95             mFormat = Format_Invalid;
96             mSampleRate = 0;
97         } else {
98             mFormat = mInputSource->format();
99             mSampleRate = Format_sampleRate(mFormat);
100 #if !LOG_NDEBUG
101             unsigned channelCount = Format_channelCount(mFormat);
102             ALOG_ASSERT(channelCount >= 1 && channelCount <= FCC_LIMIT);
103 #endif
104         }
105         dumpState->mSampleRate = mSampleRate;
106         eitherChanged = true;
107     }
108 
109     // check for change in pipe
110     if (current->mPipeSinkGen != mPipeSinkGen) {
111         mPipeSink = current->mPipeSink;
112         mPipeSinkGen = current->mPipeSinkGen;
113         eitherChanged = true;
114     }
115 
116     // input source and pipe sink must be compatible
117     if (eitherChanged && mInputSource != nullptr && mPipeSink != nullptr) {
118         ALOG_ASSERT(Format_isEqual(mFormat, mPipeSink->format()));
119     }
120 
121     if ((!Format_isEqual(mFormat, previousFormat)) || (frameCount != previous->mFrameCount)) {
122         // FIXME to avoid priority inversion, don't free here
123         free(mReadBuffer);
124         mReadBuffer = nullptr;
125         if (frameCount > 0 && mSampleRate > 0) {
126             // FIXME new may block for unbounded time at internal mutex of the heap
127             //       implementation; it would be better to have normal capture thread allocate for
128             //       us to avoid blocking here and to prevent possible priority inversion
129             const size_t bufferSize = frameCount * Format_frameSize(mFormat);
130             (void)posix_memalign(&mReadBuffer, 32, bufferSize);
131             memset(mReadBuffer, 0, bufferSize); // if posix_memalign fails, will segv here.
132             mPeriodNs = (frameCount * 1000000000LL) / mSampleRate;      // 1.00
133             mUnderrunNs = (frameCount * 1750000000LL) / mSampleRate;    // 1.75
134             mOverrunNs = (frameCount * 500000000LL) / mSampleRate;      // 0.50
135             mForceNs = (frameCount * 950000000LL) / mSampleRate;        // 0.95
136             mWarmupNsMin = (frameCount * 750000000LL) / mSampleRate;    // 0.75
137             mWarmupNsMax = (frameCount * 1250000000LL) / mSampleRate;   // 1.25
138         } else {
139             mPeriodNs = 0;
140             mUnderrunNs = 0;
141             mOverrunNs = 0;
142             mForceNs = 0;
143             mWarmupNsMin = 0;
144             mWarmupNsMax = LONG_MAX;
145         }
146         mReadBufferState = -1;
147         dumpState->mFrameCount = frameCount;
148     }
149     dumpState->mSilenced = current->mSilenceCapture;
150 }
151 
onWork()152 void FastCapture::onWork()
153 {
154     const FastCaptureState * const current = (const FastCaptureState *) mCurrent;
155     FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) mDumpState;
156     const FastCaptureState::Command command = mCommand;
157     size_t frameCount = current->mFrameCount;
158     AudioBufferProvider* fastPatchRecordBufferProvider = current->mFastPatchRecordBufferProvider;
159     AudioBufferProvider::Buffer patchBuffer;
160 
161     if (fastPatchRecordBufferProvider != nullptr) {
162         patchBuffer.frameCount = ~0;
163         const status_t status = fastPatchRecordBufferProvider->getNextBuffer(&patchBuffer);
164         if (status != NO_ERROR) {
165             frameCount = 0;
166         } else if (patchBuffer.frameCount < frameCount) {
167             // TODO: Make sure that it doesn't cause any issues if we just get a small available
168             // buffer from the buffer provider.
169             frameCount = patchBuffer.frameCount;
170         }
171     }
172 
173     if ((command & FastCaptureState::READ) /*&& isWarm*/) {
174         ALOG_ASSERT(mInputSource != nullptr);
175         ALOG_ASSERT(mReadBuffer != nullptr);
176         dumpState->mReadSequence++;
177         ATRACE_BEGIN("read");
178         const ssize_t framesRead = mInputSource->read(mReadBuffer, frameCount);
179         ATRACE_END();
180         dumpState->mReadSequence++;
181         if (framesRead >= 0) {
182             LOG_ALWAYS_FATAL_IF((size_t) framesRead > frameCount);
183             mTotalNativeFramesRead += framesRead;
184             dumpState->mFramesRead = mTotalNativeFramesRead;
185             mReadBufferState = framesRead;
186             patchBuffer.frameCount = framesRead;
187         } else {
188             dumpState->mReadErrors++;
189             mReadBufferState = 0;
190         }
191         // FIXME rename to attemptedIO
192         mAttemptedWrite = true;
193     }
194 
195     if (command & FastCaptureState::WRITE) {
196         ALOG_ASSERT(mPipeSink != nullptr);
197         ALOG_ASSERT(mReadBuffer != nullptr);
198         if (mReadBufferState < 0) {
199             memset(mReadBuffer, 0, frameCount * Format_frameSize(mFormat));
200             mReadBufferState = frameCount;
201         }
202         if (mReadBufferState > 0) {
203             if (current->mSilenceCapture) {
204                 memset(mReadBuffer, 0, mReadBufferState * Format_frameSize(mFormat));
205             }
206             const ssize_t framesWritten = mPipeSink->write(mReadBuffer, mReadBufferState);
207             audio_track_cblk_t* cblk = current->mCblk;
208             if (fastPatchRecordBufferProvider != nullptr) {
209                 // This indicates the fast track is a patch record, update the cblk by
210                 // calling releaseBuffer().
211                 memcpy_by_audio_format(patchBuffer.raw, current->mFastPatchRecordFormat,
212                         mReadBuffer, mFormat.mFormat, framesWritten * mFormat.mChannelCount);
213                 patchBuffer.frameCount = framesWritten;
214                 fastPatchRecordBufferProvider->releaseBuffer(&patchBuffer);
215             } else if (cblk != nullptr && framesWritten > 0) {
216                 // FIXME This supports at most one fast capture client.
217                 //       To handle multiple clients this could be converted to an array,
218                 //       or with a lot more work the control block could be shared by all clients.
219                 const int32_t rear = cblk->u.mStreaming.mRear;
220                 android_atomic_release_store(framesWritten + rear, &cblk->u.mStreaming.mRear);
221                 cblk->mServer += framesWritten;
222                 const int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
223                 if (!(old & CBLK_FUTEX_WAKE)) {
224                     // client is never in server process, so don't use FUTEX_WAKE_PRIVATE
225                     (void) syscall(__NR_futex, &cblk->mFutex, FUTEX_WAKE, 1);
226                 }
227             }
228         }
229     }
230 }
231 
232 }   // namespace android
233