blob: 873a9adf2617fd754427db95e089fe2716d9583b [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"
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
30namespace android {
31
Glenn Kastene4a7ce22015-03-03 11:23:17 -080032/*static*/ const FastCaptureState FastCapture::sInitial;
Glenn Kastenf91df1b2014-03-13 14:59:31 -070033
Glenn Kastenf9715e42016-07-13 14:02:03 -070034FastCapture::FastCapture() : FastThread("cycleC_ms", "loadC_us"),
Glenn Kastene4a7ce22015-03-03 11:23:17 -080035 mInputSource(NULL), mInputSourceGen(0), mPipeSink(NULL), mPipeSinkGen(0),
36 mReadBuffer(NULL), mReadBufferState(-1), mFormat(Format_Invalid), mSampleRate(0),
37 // mDummyDumpState
38 mTotalNativeFramesRead(0)
Glenn Kastenf91df1b2014-03-13 14:59:31 -070039{
Glenn Kastene4a7ce22015-03-03 11:23:17 -080040 mPrevious = &sInitial;
41 mCurrent = &sInitial;
Glenn Kastenf91df1b2014-03-13 14:59:31 -070042
Glenn Kastene4a7ce22015-03-03 11:23:17 -080043 mDummyDumpState = &mDummyFastCaptureDumpState;
Glenn Kastenf91df1b2014-03-13 14:59:31 -070044}
45
46FastCapture::~FastCapture()
47{
48}
49
50FastCaptureStateQueue* FastCapture::sq()
51{
52 return &mSQ;
53}
54
55const FastThreadState *FastCapture::poll()
56{
57 return mSQ.poll();
58}
59
60void FastCapture::setLog(NBLog::Writer *logWriter __unused)
61{
62}
63
64void FastCapture::onIdle()
65{
Glenn Kastene4a7ce22015-03-03 11:23:17 -080066 mPreIdle = *(const FastCaptureState *)mCurrent;
67 mCurrent = &mPreIdle;
Glenn Kastenf91df1b2014-03-13 14:59:31 -070068}
69
70void FastCapture::onExit()
71{
Glenn Kasten51157772015-03-03 11:48:45 -080072 free(mReadBuffer);
Glenn Kastenf91df1b2014-03-13 14:59:31 -070073}
74
75bool 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
87void FastCapture::onStateChange()
88{
Glenn Kasten4dd03b52015-03-03 11:32:04 -080089 const FastCaptureState * const current = (const FastCaptureState *) mCurrent;
90 const FastCaptureState * const previous = (const FastCaptureState *) mPrevious;
91 FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) mDumpState;
Glenn Kastenf91df1b2014-03-13 14:59:31 -070092 const size_t frameCount = current->mFrameCount;
93
94 bool eitherChanged = false;
95
96 // check for change in input HAL configuration
Glenn Kastene4a7ce22015-03-03 11:23:17 -080097 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;
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700104 } else {
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800105 mFormat = mInputSource->format();
106 mSampleRate = Format_sampleRate(mFormat);
Glenn Kasten57c4e6f2016-03-18 14:54:07 -0700107#if !LOG_NDEBUG
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800108 unsigned channelCount = Format_channelCount(mFormat);
Andy Hungd330ee42015-04-20 13:23:41 -0700109 ALOG_ASSERT(channelCount >= 1 && channelCount <= FCC_8);
Glenn Kasten57c4e6f2016-03-18 14:54:07 -0700110#endif
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700111 }
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800112 dumpState->mSampleRate = mSampleRate;
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700113 eitherChanged = true;
114 }
115
116 // check for change in pipe
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800117 if (current->mPipeSinkGen != mPipeSinkGen) {
118 mPipeSink = current->mPipeSink;
119 mPipeSinkGen = current->mPipeSinkGen;
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700120 eitherChanged = true;
121 }
122
123 // input source and pipe sink must be compatible
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800124 if (eitherChanged && mInputSource != NULL && mPipeSink != NULL) {
125 ALOG_ASSERT(Format_isEqual(mFormat, mPipeSink->format()));
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700126 }
127
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800128 if ((!Format_isEqual(mFormat, previousFormat)) || (frameCount != previous->mFrameCount)) {
Glenn Kasten51157772015-03-03 11:48:45 -0800129 // FIXME to avoid priority inversion, don't free here
130 free(mReadBuffer);
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800131 mReadBuffer = NULL;
132 if (frameCount > 0 && mSampleRate > 0) {
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700133 // 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
Andy Hung0a01c2f2015-09-21 12:44:54 -0700136 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.
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800139 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
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700145 } else {
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800146 mPeriodNs = 0;
147 mUnderrunNs = 0;
148 mOverrunNs = 0;
149 mForceNs = 0;
150 mWarmupNsMin = 0;
151 mWarmupNsMax = LONG_MAX;
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700152 }
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800153 mReadBufferState = -1;
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700154 dumpState->mFrameCount = frameCount;
155 }
156
157}
158
159void FastCapture::onWork()
160{
Glenn Kasten4dd03b52015-03-03 11:32:04 -0800161 const FastCaptureState * const current = (const FastCaptureState *) mCurrent;
162 FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) mDumpState;
163 const FastCaptureState::Command command = mCommand;
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700164 const size_t frameCount = current->mFrameCount;
165
166 if ((command & FastCaptureState::READ) /*&& isWarm*/) {
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800167 ALOG_ASSERT(mInputSource != NULL);
168 ALOG_ASSERT(mReadBuffer != NULL);
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700169 dumpState->mReadSequence++;
170 ATRACE_BEGIN("read");
Glenn Kastend79072e2016-01-06 08:41:20 -0800171 ssize_t framesRead = mInputSource->read(mReadBuffer, frameCount);
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700172 ATRACE_END();
173 dumpState->mReadSequence++;
174 if (framesRead >= 0) {
175 LOG_ALWAYS_FATAL_IF((size_t) framesRead > frameCount);
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800176 mTotalNativeFramesRead += framesRead;
177 dumpState->mFramesRead = mTotalNativeFramesRead;
178 mReadBufferState = framesRead;
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700179 } else {
180 dumpState->mReadErrors++;
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800181 mReadBufferState = 0;
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700182 }
183 // FIXME rename to attemptedIO
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800184 mAttemptedWrite = true;
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700185 }
186
187 if (command & FastCaptureState::WRITE) {
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800188 ALOG_ASSERT(mPipeSink != NULL);
189 ALOG_ASSERT(mReadBuffer != NULL);
190 if (mReadBufferState < 0) {
Glenn Kasten51157772015-03-03 11:48:45 -0800191 memset(mReadBuffer, 0, frameCount * Format_frameSize(mFormat));
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800192 mReadBufferState = frameCount;
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700193 }
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800194 if (mReadBufferState > 0) {
195 ssize_t framesWritten = mPipeSink->write(mReadBuffer, mReadBufferState);
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700196 // 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
Glenn Kastenf91df1b2014-03-13 14:59:31 -0700214} // namespace android