blob: d6d6e257cdd55d87ba9354954ebbd688352a28c5 [file] [log] [blame]
Glenn Kastenf91df1b2014-03-13 14:59:31 -07001/*
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"
jiabin01c8f562018-07-19 17:47:28 -070023#include <audio_utils/format.h>
Glenn Kastenf91df1b2014-03-13 14:59:31 -070024#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
31namespace android {
32
Glenn Kastene4a7ce22015-03-03 11:23:17 -080033/*static*/ const FastCaptureState FastCapture::sInitial;
Glenn Kastenf91df1b2014-03-13 14:59:31 -070034
Glenn Kastenf9715e42016-07-13 14:02:03 -070035FastCapture::FastCapture() : FastThread("cycleC_ms", "loadC_us"),
Glenn Kastene4a7ce22015-03-03 11:23:17 -080036 mInputSource(NULL), mInputSourceGen(0), mPipeSink(NULL), mPipeSinkGen(0),
37 mReadBuffer(NULL), mReadBufferState(-1), mFormat(Format_Invalid), mSampleRate(0),
38 // mDummyDumpState
39 mTotalNativeFramesRead(0)
Glenn Kastenf91df1b2014-03-13 14:59:31 -070040{
Glenn Kastene4a7ce22015-03-03 11:23:17 -080041 mPrevious = &sInitial;
42 mCurrent = &sInitial;
Glenn Kastenf91df1b2014-03-13 14:59:31 -070043
Glenn Kastene4a7ce22015-03-03 11:23:17 -080044 mDummyDumpState = &mDummyFastCaptureDumpState;
Glenn Kastenf91df1b2014-03-13 14:59:31 -070045}
46
47FastCapture::~FastCapture()
48{
49}
50
51FastCaptureStateQueue* FastCapture::sq()
52{
53 return &mSQ;
54}
55
56const FastThreadState *FastCapture::poll()
57{
58 return mSQ.poll();
59}
60
Glenn Kasten3ab8d662017-04-03 14:35:09 -070061void FastCapture::setNBLogWriter(NBLog::Writer *logWriter __unused)
Glenn Kastenf91df1b2014-03-13 14:59:31 -070062{
63}
64
65void FastCapture::onIdle()
66{
Glenn Kastene4a7ce22015-03-03 11:23:17 -080067 mPreIdle = *(const FastCaptureState *)mCurrent;
68 mCurrent = &mPreIdle;
Glenn Kastenf91df1b2014-03-13 14:59:31 -070069}
70
71void FastCapture::onExit()
72{
Glenn Kasten51157772015-03-03 11:48:45 -080073 free(mReadBuffer);
Glenn Kastenf91df1b2014-03-13 14:59:31 -070074}
75
76bool 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
88void FastCapture::onStateChange()
89{
Glenn Kasten4dd03b52015-03-03 11:32:04 -080090 const FastCaptureState * const current = (const FastCaptureState *) mCurrent;
91 const FastCaptureState * const previous = (const FastCaptureState *) mPrevious;
92 FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) mDumpState;
Glenn Kastenf91df1b2014-03-13 14:59:31 -070093 const size_t frameCount = current->mFrameCount;
94
95 bool eitherChanged = false;
96
97 // check for change in input HAL configuration
Glenn Kastene4a7ce22015-03-03 11:23:17 -080098 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;
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700105 } else {
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800106 mFormat = mInputSource->format();
107 mSampleRate = Format_sampleRate(mFormat);
Glenn Kasten57c4e6f2016-03-18 14:54:07 -0700108#if !LOG_NDEBUG
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800109 unsigned channelCount = Format_channelCount(mFormat);
Andy Hungd330ee42015-04-20 13:23:41 -0700110 ALOG_ASSERT(channelCount >= 1 && channelCount <= FCC_8);
Glenn Kasten57c4e6f2016-03-18 14:54:07 -0700111#endif
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700112 }
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800113 dumpState->mSampleRate = mSampleRate;
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700114 eitherChanged = true;
115 }
116
117 // check for change in pipe
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800118 if (current->mPipeSinkGen != mPipeSinkGen) {
119 mPipeSink = current->mPipeSink;
120 mPipeSinkGen = current->mPipeSinkGen;
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700121 eitherChanged = true;
122 }
123
124 // input source and pipe sink must be compatible
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800125 if (eitherChanged && mInputSource != NULL && mPipeSink != NULL) {
126 ALOG_ASSERT(Format_isEqual(mFormat, mPipeSink->format()));
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700127 }
128
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800129 if ((!Format_isEqual(mFormat, previousFormat)) || (frameCount != previous->mFrameCount)) {
Glenn Kasten51157772015-03-03 11:48:45 -0800130 // FIXME to avoid priority inversion, don't free here
131 free(mReadBuffer);
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800132 mReadBuffer = NULL;
133 if (frameCount > 0 && mSampleRate > 0) {
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700134 // 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
Andy Hung0a01c2f2015-09-21 12:44:54 -0700137 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.
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800140 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
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700146 } else {
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800147 mPeriodNs = 0;
148 mUnderrunNs = 0;
149 mOverrunNs = 0;
150 mForceNs = 0;
151 mWarmupNsMin = 0;
152 mWarmupNsMax = LONG_MAX;
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700153 }
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800154 mReadBufferState = -1;
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700155 dumpState->mFrameCount = frameCount;
156 }
Eric Laurent33403f02020-05-29 18:35:06 -0700157 dumpState->mSilenced = current->mSilenceCapture;
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700158}
159
160void FastCapture::onWork()
161{
Glenn Kasten4dd03b52015-03-03 11:32:04 -0800162 const FastCaptureState * const current = (const FastCaptureState *) mCurrent;
163 FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) mDumpState;
164 const FastCaptureState::Command command = mCommand;
jiabin01c8f562018-07-19 17:47:28 -0700165 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 }
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700180
181 if ((command & FastCaptureState::READ) /*&& isWarm*/) {
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800182 ALOG_ASSERT(mInputSource != NULL);
183 ALOG_ASSERT(mReadBuffer != NULL);
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700184 dumpState->mReadSequence++;
185 ATRACE_BEGIN("read");
Glenn Kastend79072e2016-01-06 08:41:20 -0800186 ssize_t framesRead = mInputSource->read(mReadBuffer, frameCount);
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700187 ATRACE_END();
188 dumpState->mReadSequence++;
189 if (framesRead >= 0) {
190 LOG_ALWAYS_FATAL_IF((size_t) framesRead > frameCount);
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800191 mTotalNativeFramesRead += framesRead;
192 dumpState->mFramesRead = mTotalNativeFramesRead;
193 mReadBufferState = framesRead;
jiabin01c8f562018-07-19 17:47:28 -0700194 patchBuffer.frameCount = framesRead;
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700195 } else {
196 dumpState->mReadErrors++;
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800197 mReadBufferState = 0;
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700198 }
199 // FIXME rename to attemptedIO
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800200 mAttemptedWrite = true;
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700201 }
202
203 if (command & FastCaptureState::WRITE) {
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800204 ALOG_ASSERT(mPipeSink != NULL);
205 ALOG_ASSERT(mReadBuffer != NULL);
206 if (mReadBufferState < 0) {
Glenn Kasten51157772015-03-03 11:48:45 -0800207 memset(mReadBuffer, 0, frameCount * Format_frameSize(mFormat));
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800208 mReadBufferState = frameCount;
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700209 }
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800210 if (mReadBufferState > 0) {
Eric Laurent33403f02020-05-29 18:35:06 -0700211 if (current->mSilenceCapture) {
212 memset(mReadBuffer, 0, mReadBufferState * Format_frameSize(mFormat));
213 }
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800214 ssize_t framesWritten = mPipeSink->write(mReadBuffer, mReadBufferState);
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700215 audio_track_cblk_t* cblk = current->mCblk;
jiabin01c8f562018-07-19 17:47:28 -0700216 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.
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700227 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
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700240} // namespace android