xref: /aosp_15_r20/frameworks/av/services/audioflinger/fastpath/FastCapture.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker  * Copyright (C) 2014 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker  *
4*ec779b8eSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker  *
8*ec779b8eSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker  *
10*ec779b8eSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker  * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker  */
16*ec779b8eSAndroid Build Coastguard Worker 
17*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "FastCapture"
18*ec779b8eSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
19*ec779b8eSAndroid Build Coastguard Worker 
20*ec779b8eSAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_AUDIO
21*ec779b8eSAndroid Build Coastguard Worker 
22*ec779b8eSAndroid Build Coastguard Worker #include "Configuration.h"
23*ec779b8eSAndroid Build Coastguard Worker #include <audio_utils/format.h>
24*ec779b8eSAndroid Build Coastguard Worker #include <linux/futex.h>
25*ec779b8eSAndroid Build Coastguard Worker #include <sys/syscall.h>
26*ec779b8eSAndroid Build Coastguard Worker #include <media/AudioBufferProvider.h>
27*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
28*ec779b8eSAndroid Build Coastguard Worker #include <utils/Trace.h>
29*ec779b8eSAndroid Build Coastguard Worker #include "FastCapture.h"
30*ec779b8eSAndroid Build Coastguard Worker 
31*ec779b8eSAndroid Build Coastguard Worker namespace android {
32*ec779b8eSAndroid Build Coastguard Worker 
33*ec779b8eSAndroid Build Coastguard Worker /*static*/ const FastCaptureState FastCapture::sInitial{};
34*ec779b8eSAndroid Build Coastguard Worker 
FastCapture()35*ec779b8eSAndroid Build Coastguard Worker FastCapture::FastCapture() : FastThread("cycleC_ms", "loadC_us")
36*ec779b8eSAndroid Build Coastguard Worker {
37*ec779b8eSAndroid Build Coastguard Worker     // base class initialization
38*ec779b8eSAndroid Build Coastguard Worker     mPrevious = &sInitial;
39*ec779b8eSAndroid Build Coastguard Worker     mCurrent = &sInitial;
40*ec779b8eSAndroid Build Coastguard Worker     mDummyDumpState = &mDummyFastCaptureDumpState;
41*ec779b8eSAndroid Build Coastguard Worker }
42*ec779b8eSAndroid Build Coastguard Worker 
sq()43*ec779b8eSAndroid Build Coastguard Worker FastCaptureStateQueue* FastCapture::sq()
44*ec779b8eSAndroid Build Coastguard Worker {
45*ec779b8eSAndroid Build Coastguard Worker     return &mSQ;
46*ec779b8eSAndroid Build Coastguard Worker }
47*ec779b8eSAndroid Build Coastguard Worker 
poll()48*ec779b8eSAndroid Build Coastguard Worker const FastThreadState *FastCapture::poll()
49*ec779b8eSAndroid Build Coastguard Worker {
50*ec779b8eSAndroid Build Coastguard Worker     return mSQ.poll();
51*ec779b8eSAndroid Build Coastguard Worker }
52*ec779b8eSAndroid Build Coastguard Worker 
setNBLogWriter(NBLog::Writer * logWriter __unused)53*ec779b8eSAndroid Build Coastguard Worker void FastCapture::setNBLogWriter(NBLog::Writer *logWriter __unused)
54*ec779b8eSAndroid Build Coastguard Worker {
55*ec779b8eSAndroid Build Coastguard Worker }
56*ec779b8eSAndroid Build Coastguard Worker 
onIdle()57*ec779b8eSAndroid Build Coastguard Worker void FastCapture::onIdle()
58*ec779b8eSAndroid Build Coastguard Worker {
59*ec779b8eSAndroid Build Coastguard Worker     mPreIdle = *(const FastCaptureState *)mCurrent;
60*ec779b8eSAndroid Build Coastguard Worker     mCurrent = &mPreIdle;
61*ec779b8eSAndroid Build Coastguard Worker }
62*ec779b8eSAndroid Build Coastguard Worker 
onExit()63*ec779b8eSAndroid Build Coastguard Worker void FastCapture::onExit()
64*ec779b8eSAndroid Build Coastguard Worker {
65*ec779b8eSAndroid Build Coastguard Worker     free(mReadBuffer);
66*ec779b8eSAndroid Build Coastguard Worker }
67*ec779b8eSAndroid Build Coastguard Worker 
isSubClassCommand(FastThreadState::Command command)68*ec779b8eSAndroid Build Coastguard Worker bool FastCapture::isSubClassCommand(FastThreadState::Command command)
69*ec779b8eSAndroid Build Coastguard Worker {
70*ec779b8eSAndroid Build Coastguard Worker     switch ((FastCaptureState::Command) command) {
71*ec779b8eSAndroid Build Coastguard Worker     case FastCaptureState::READ:
72*ec779b8eSAndroid Build Coastguard Worker     case FastCaptureState::WRITE:
73*ec779b8eSAndroid Build Coastguard Worker     case FastCaptureState::READ_WRITE:
74*ec779b8eSAndroid Build Coastguard Worker         return true;
75*ec779b8eSAndroid Build Coastguard Worker     default:
76*ec779b8eSAndroid Build Coastguard Worker         return false;
77*ec779b8eSAndroid Build Coastguard Worker     }
78*ec779b8eSAndroid Build Coastguard Worker }
79*ec779b8eSAndroid Build Coastguard Worker 
onStateChange()80*ec779b8eSAndroid Build Coastguard Worker void FastCapture::onStateChange()
81*ec779b8eSAndroid Build Coastguard Worker {
82*ec779b8eSAndroid Build Coastguard Worker     const FastCaptureState * const current = (const FastCaptureState *) mCurrent;
83*ec779b8eSAndroid Build Coastguard Worker     const FastCaptureState * const previous = (const FastCaptureState *) mPrevious;
84*ec779b8eSAndroid Build Coastguard Worker     FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) mDumpState;
85*ec779b8eSAndroid Build Coastguard Worker     const size_t frameCount = current->mFrameCount;
86*ec779b8eSAndroid Build Coastguard Worker 
87*ec779b8eSAndroid Build Coastguard Worker     bool eitherChanged = false;
88*ec779b8eSAndroid Build Coastguard Worker 
89*ec779b8eSAndroid Build Coastguard Worker     // check for change in input HAL configuration
90*ec779b8eSAndroid Build Coastguard Worker     const NBAIO_Format previousFormat = mFormat;
91*ec779b8eSAndroid Build Coastguard Worker     if (current->mInputSourceGen != mInputSourceGen) {
92*ec779b8eSAndroid Build Coastguard Worker         mInputSource = current->mInputSource;
93*ec779b8eSAndroid Build Coastguard Worker         mInputSourceGen = current->mInputSourceGen;
94*ec779b8eSAndroid Build Coastguard Worker         if (mInputSource == nullptr) {
95*ec779b8eSAndroid Build Coastguard Worker             mFormat = Format_Invalid;
96*ec779b8eSAndroid Build Coastguard Worker             mSampleRate = 0;
97*ec779b8eSAndroid Build Coastguard Worker         } else {
98*ec779b8eSAndroid Build Coastguard Worker             mFormat = mInputSource->format();
99*ec779b8eSAndroid Build Coastguard Worker             mSampleRate = Format_sampleRate(mFormat);
100*ec779b8eSAndroid Build Coastguard Worker #if !LOG_NDEBUG
101*ec779b8eSAndroid Build Coastguard Worker             unsigned channelCount = Format_channelCount(mFormat);
102*ec779b8eSAndroid Build Coastguard Worker             ALOG_ASSERT(channelCount >= 1 && channelCount <= FCC_LIMIT);
103*ec779b8eSAndroid Build Coastguard Worker #endif
104*ec779b8eSAndroid Build Coastguard Worker         }
105*ec779b8eSAndroid Build Coastguard Worker         dumpState->mSampleRate = mSampleRate;
106*ec779b8eSAndroid Build Coastguard Worker         eitherChanged = true;
107*ec779b8eSAndroid Build Coastguard Worker     }
108*ec779b8eSAndroid Build Coastguard Worker 
109*ec779b8eSAndroid Build Coastguard Worker     // check for change in pipe
110*ec779b8eSAndroid Build Coastguard Worker     if (current->mPipeSinkGen != mPipeSinkGen) {
111*ec779b8eSAndroid Build Coastguard Worker         mPipeSink = current->mPipeSink;
112*ec779b8eSAndroid Build Coastguard Worker         mPipeSinkGen = current->mPipeSinkGen;
113*ec779b8eSAndroid Build Coastguard Worker         eitherChanged = true;
114*ec779b8eSAndroid Build Coastguard Worker     }
115*ec779b8eSAndroid Build Coastguard Worker 
116*ec779b8eSAndroid Build Coastguard Worker     // input source and pipe sink must be compatible
117*ec779b8eSAndroid Build Coastguard Worker     if (eitherChanged && mInputSource != nullptr && mPipeSink != nullptr) {
118*ec779b8eSAndroid Build Coastguard Worker         ALOG_ASSERT(Format_isEqual(mFormat, mPipeSink->format()));
119*ec779b8eSAndroid Build Coastguard Worker     }
120*ec779b8eSAndroid Build Coastguard Worker 
121*ec779b8eSAndroid Build Coastguard Worker     if ((!Format_isEqual(mFormat, previousFormat)) || (frameCount != previous->mFrameCount)) {
122*ec779b8eSAndroid Build Coastguard Worker         // FIXME to avoid priority inversion, don't free here
123*ec779b8eSAndroid Build Coastguard Worker         free(mReadBuffer);
124*ec779b8eSAndroid Build Coastguard Worker         mReadBuffer = nullptr;
125*ec779b8eSAndroid Build Coastguard Worker         if (frameCount > 0 && mSampleRate > 0) {
126*ec779b8eSAndroid Build Coastguard Worker             // FIXME new may block for unbounded time at internal mutex of the heap
127*ec779b8eSAndroid Build Coastguard Worker             //       implementation; it would be better to have normal capture thread allocate for
128*ec779b8eSAndroid Build Coastguard Worker             //       us to avoid blocking here and to prevent possible priority inversion
129*ec779b8eSAndroid Build Coastguard Worker             const size_t bufferSize = frameCount * Format_frameSize(mFormat);
130*ec779b8eSAndroid Build Coastguard Worker             (void)posix_memalign(&mReadBuffer, 32, bufferSize);
131*ec779b8eSAndroid Build Coastguard Worker             memset(mReadBuffer, 0, bufferSize); // if posix_memalign fails, will segv here.
132*ec779b8eSAndroid Build Coastguard Worker             mPeriodNs = (frameCount * 1000000000LL) / mSampleRate;      // 1.00
133*ec779b8eSAndroid Build Coastguard Worker             mUnderrunNs = (frameCount * 1750000000LL) / mSampleRate;    // 1.75
134*ec779b8eSAndroid Build Coastguard Worker             mOverrunNs = (frameCount * 500000000LL) / mSampleRate;      // 0.50
135*ec779b8eSAndroid Build Coastguard Worker             mForceNs = (frameCount * 950000000LL) / mSampleRate;        // 0.95
136*ec779b8eSAndroid Build Coastguard Worker             mWarmupNsMin = (frameCount * 750000000LL) / mSampleRate;    // 0.75
137*ec779b8eSAndroid Build Coastguard Worker             mWarmupNsMax = (frameCount * 1250000000LL) / mSampleRate;   // 1.25
138*ec779b8eSAndroid Build Coastguard Worker         } else {
139*ec779b8eSAndroid Build Coastguard Worker             mPeriodNs = 0;
140*ec779b8eSAndroid Build Coastguard Worker             mUnderrunNs = 0;
141*ec779b8eSAndroid Build Coastguard Worker             mOverrunNs = 0;
142*ec779b8eSAndroid Build Coastguard Worker             mForceNs = 0;
143*ec779b8eSAndroid Build Coastguard Worker             mWarmupNsMin = 0;
144*ec779b8eSAndroid Build Coastguard Worker             mWarmupNsMax = LONG_MAX;
145*ec779b8eSAndroid Build Coastguard Worker         }
146*ec779b8eSAndroid Build Coastguard Worker         mReadBufferState = -1;
147*ec779b8eSAndroid Build Coastguard Worker         dumpState->mFrameCount = frameCount;
148*ec779b8eSAndroid Build Coastguard Worker     }
149*ec779b8eSAndroid Build Coastguard Worker     dumpState->mSilenced = current->mSilenceCapture;
150*ec779b8eSAndroid Build Coastguard Worker }
151*ec779b8eSAndroid Build Coastguard Worker 
onWork()152*ec779b8eSAndroid Build Coastguard Worker void FastCapture::onWork()
153*ec779b8eSAndroid Build Coastguard Worker {
154*ec779b8eSAndroid Build Coastguard Worker     const FastCaptureState * const current = (const FastCaptureState *) mCurrent;
155*ec779b8eSAndroid Build Coastguard Worker     FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) mDumpState;
156*ec779b8eSAndroid Build Coastguard Worker     const FastCaptureState::Command command = mCommand;
157*ec779b8eSAndroid Build Coastguard Worker     size_t frameCount = current->mFrameCount;
158*ec779b8eSAndroid Build Coastguard Worker     AudioBufferProvider* fastPatchRecordBufferProvider = current->mFastPatchRecordBufferProvider;
159*ec779b8eSAndroid Build Coastguard Worker     AudioBufferProvider::Buffer patchBuffer;
160*ec779b8eSAndroid Build Coastguard Worker 
161*ec779b8eSAndroid Build Coastguard Worker     if (fastPatchRecordBufferProvider != nullptr) {
162*ec779b8eSAndroid Build Coastguard Worker         patchBuffer.frameCount = ~0;
163*ec779b8eSAndroid Build Coastguard Worker         const status_t status = fastPatchRecordBufferProvider->getNextBuffer(&patchBuffer);
164*ec779b8eSAndroid Build Coastguard Worker         if (status != NO_ERROR) {
165*ec779b8eSAndroid Build Coastguard Worker             frameCount = 0;
166*ec779b8eSAndroid Build Coastguard Worker         } else if (patchBuffer.frameCount < frameCount) {
167*ec779b8eSAndroid Build Coastguard Worker             // TODO: Make sure that it doesn't cause any issues if we just get a small available
168*ec779b8eSAndroid Build Coastguard Worker             // buffer from the buffer provider.
169*ec779b8eSAndroid Build Coastguard Worker             frameCount = patchBuffer.frameCount;
170*ec779b8eSAndroid Build Coastguard Worker         }
171*ec779b8eSAndroid Build Coastguard Worker     }
172*ec779b8eSAndroid Build Coastguard Worker 
173*ec779b8eSAndroid Build Coastguard Worker     if ((command & FastCaptureState::READ) /*&& isWarm*/) {
174*ec779b8eSAndroid Build Coastguard Worker         ALOG_ASSERT(mInputSource != nullptr);
175*ec779b8eSAndroid Build Coastguard Worker         ALOG_ASSERT(mReadBuffer != nullptr);
176*ec779b8eSAndroid Build Coastguard Worker         dumpState->mReadSequence++;
177*ec779b8eSAndroid Build Coastguard Worker         ATRACE_BEGIN("read");
178*ec779b8eSAndroid Build Coastguard Worker         const ssize_t framesRead = mInputSource->read(mReadBuffer, frameCount);
179*ec779b8eSAndroid Build Coastguard Worker         ATRACE_END();
180*ec779b8eSAndroid Build Coastguard Worker         dumpState->mReadSequence++;
181*ec779b8eSAndroid Build Coastguard Worker         if (framesRead >= 0) {
182*ec779b8eSAndroid Build Coastguard Worker             LOG_ALWAYS_FATAL_IF((size_t) framesRead > frameCount);
183*ec779b8eSAndroid Build Coastguard Worker             mTotalNativeFramesRead += framesRead;
184*ec779b8eSAndroid Build Coastguard Worker             dumpState->mFramesRead = mTotalNativeFramesRead;
185*ec779b8eSAndroid Build Coastguard Worker             mReadBufferState = framesRead;
186*ec779b8eSAndroid Build Coastguard Worker             patchBuffer.frameCount = framesRead;
187*ec779b8eSAndroid Build Coastguard Worker         } else {
188*ec779b8eSAndroid Build Coastguard Worker             dumpState->mReadErrors++;
189*ec779b8eSAndroid Build Coastguard Worker             mReadBufferState = 0;
190*ec779b8eSAndroid Build Coastguard Worker         }
191*ec779b8eSAndroid Build Coastguard Worker         // FIXME rename to attemptedIO
192*ec779b8eSAndroid Build Coastguard Worker         mAttemptedWrite = true;
193*ec779b8eSAndroid Build Coastguard Worker     }
194*ec779b8eSAndroid Build Coastguard Worker 
195*ec779b8eSAndroid Build Coastguard Worker     if (command & FastCaptureState::WRITE) {
196*ec779b8eSAndroid Build Coastguard Worker         ALOG_ASSERT(mPipeSink != nullptr);
197*ec779b8eSAndroid Build Coastguard Worker         ALOG_ASSERT(mReadBuffer != nullptr);
198*ec779b8eSAndroid Build Coastguard Worker         if (mReadBufferState < 0) {
199*ec779b8eSAndroid Build Coastguard Worker             memset(mReadBuffer, 0, frameCount * Format_frameSize(mFormat));
200*ec779b8eSAndroid Build Coastguard Worker             mReadBufferState = frameCount;
201*ec779b8eSAndroid Build Coastguard Worker         }
202*ec779b8eSAndroid Build Coastguard Worker         if (mReadBufferState > 0) {
203*ec779b8eSAndroid Build Coastguard Worker             if (current->mSilenceCapture) {
204*ec779b8eSAndroid Build Coastguard Worker                 memset(mReadBuffer, 0, mReadBufferState * Format_frameSize(mFormat));
205*ec779b8eSAndroid Build Coastguard Worker             }
206*ec779b8eSAndroid Build Coastguard Worker             const ssize_t framesWritten = mPipeSink->write(mReadBuffer, mReadBufferState);
207*ec779b8eSAndroid Build Coastguard Worker             audio_track_cblk_t* cblk = current->mCblk;
208*ec779b8eSAndroid Build Coastguard Worker             if (fastPatchRecordBufferProvider != nullptr) {
209*ec779b8eSAndroid Build Coastguard Worker                 // This indicates the fast track is a patch record, update the cblk by
210*ec779b8eSAndroid Build Coastguard Worker                 // calling releaseBuffer().
211*ec779b8eSAndroid Build Coastguard Worker                 memcpy_by_audio_format(patchBuffer.raw, current->mFastPatchRecordFormat,
212*ec779b8eSAndroid Build Coastguard Worker                         mReadBuffer, mFormat.mFormat, framesWritten * mFormat.mChannelCount);
213*ec779b8eSAndroid Build Coastguard Worker                 patchBuffer.frameCount = framesWritten;
214*ec779b8eSAndroid Build Coastguard Worker                 fastPatchRecordBufferProvider->releaseBuffer(&patchBuffer);
215*ec779b8eSAndroid Build Coastguard Worker             } else if (cblk != nullptr && framesWritten > 0) {
216*ec779b8eSAndroid Build Coastguard Worker                 // FIXME This supports at most one fast capture client.
217*ec779b8eSAndroid Build Coastguard Worker                 //       To handle multiple clients this could be converted to an array,
218*ec779b8eSAndroid Build Coastguard Worker                 //       or with a lot more work the control block could be shared by all clients.
219*ec779b8eSAndroid Build Coastguard Worker                 const int32_t rear = cblk->u.mStreaming.mRear;
220*ec779b8eSAndroid Build Coastguard Worker                 android_atomic_release_store(framesWritten + rear, &cblk->u.mStreaming.mRear);
221*ec779b8eSAndroid Build Coastguard Worker                 cblk->mServer += framesWritten;
222*ec779b8eSAndroid Build Coastguard Worker                 const int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
223*ec779b8eSAndroid Build Coastguard Worker                 if (!(old & CBLK_FUTEX_WAKE)) {
224*ec779b8eSAndroid Build Coastguard Worker                     // client is never in server process, so don't use FUTEX_WAKE_PRIVATE
225*ec779b8eSAndroid Build Coastguard Worker                     (void) syscall(__NR_futex, &cblk->mFutex, FUTEX_WAKE, 1);
226*ec779b8eSAndroid Build Coastguard Worker                 }
227*ec779b8eSAndroid Build Coastguard Worker             }
228*ec779b8eSAndroid Build Coastguard Worker         }
229*ec779b8eSAndroid Build Coastguard Worker     }
230*ec779b8eSAndroid Build Coastguard Worker }
231*ec779b8eSAndroid Build Coastguard Worker 
232*ec779b8eSAndroid Build Coastguard Worker }   // namespace android
233