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(),
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
setLog(NBLog::Writer * logWriter __unused)60 void FastCapture::setLog(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 unsigned channelCount = Format_channelCount(mFormat);
108 ALOG_ASSERT(channelCount >= 1 && channelCount <= FCC_8);
109 }
110 dumpState->mSampleRate = mSampleRate;
111 eitherChanged = true;
112 }
113
114 // check for change in pipe
115 if (current->mPipeSinkGen != mPipeSinkGen) {
116 mPipeSink = current->mPipeSink;
117 mPipeSinkGen = current->mPipeSinkGen;
118 eitherChanged = true;
119 }
120
121 // input source and pipe sink must be compatible
122 if (eitherChanged && mInputSource != NULL && mPipeSink != NULL) {
123 ALOG_ASSERT(Format_isEqual(mFormat, mPipeSink->format()));
124 }
125
126 if ((!Format_isEqual(mFormat, previousFormat)) || (frameCount != previous->mFrameCount)) {
127 // FIXME to avoid priority inversion, don't free here
128 free(mReadBuffer);
129 mReadBuffer = NULL;
130 if (frameCount > 0 && mSampleRate > 0) {
131 // FIXME new may block for unbounded time at internal mutex of the heap
132 // implementation; it would be better to have normal capture thread allocate for
133 // us to avoid blocking here and to prevent possible priority inversion
134 (void)posix_memalign(&mReadBuffer, 32, frameCount * Format_frameSize(mFormat));
135 mPeriodNs = (frameCount * 1000000000LL) / mSampleRate; // 1.00
136 mUnderrunNs = (frameCount * 1750000000LL) / mSampleRate; // 1.75
137 mOverrunNs = (frameCount * 500000000LL) / mSampleRate; // 0.50
138 mForceNs = (frameCount * 950000000LL) / mSampleRate; // 0.95
139 mWarmupNsMin = (frameCount * 750000000LL) / mSampleRate; // 0.75
140 mWarmupNsMax = (frameCount * 1250000000LL) / mSampleRate; // 1.25
141 } else {
142 mPeriodNs = 0;
143 mUnderrunNs = 0;
144 mOverrunNs = 0;
145 mForceNs = 0;
146 mWarmupNsMin = 0;
147 mWarmupNsMax = LONG_MAX;
148 }
149 mReadBufferState = -1;
150 dumpState->mFrameCount = frameCount;
151 }
152
153 }
154
onWork()155 void FastCapture::onWork()
156 {
157 const FastCaptureState * const current = (const FastCaptureState *) mCurrent;
158 FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) mDumpState;
159 const FastCaptureState::Command command = mCommand;
160 const size_t frameCount = current->mFrameCount;
161
162 if ((command & FastCaptureState::READ) /*&& isWarm*/) {
163 ALOG_ASSERT(mInputSource != NULL);
164 ALOG_ASSERT(mReadBuffer != NULL);
165 dumpState->mReadSequence++;
166 ATRACE_BEGIN("read");
167 ssize_t framesRead = mInputSource->read(mReadBuffer, frameCount,
168 AudioBufferProvider::kInvalidPTS);
169 ATRACE_END();
170 dumpState->mReadSequence++;
171 if (framesRead >= 0) {
172 LOG_ALWAYS_FATAL_IF((size_t) framesRead > frameCount);
173 mTotalNativeFramesRead += framesRead;
174 dumpState->mFramesRead = mTotalNativeFramesRead;
175 mReadBufferState = framesRead;
176 } else {
177 dumpState->mReadErrors++;
178 mReadBufferState = 0;
179 }
180 // FIXME rename to attemptedIO
181 mAttemptedWrite = true;
182 }
183
184 if (command & FastCaptureState::WRITE) {
185 ALOG_ASSERT(mPipeSink != NULL);
186 ALOG_ASSERT(mReadBuffer != NULL);
187 if (mReadBufferState < 0) {
188 unsigned channelCount = Format_channelCount(mFormat);
189 memset(mReadBuffer, 0, frameCount * Format_frameSize(mFormat));
190 mReadBufferState = frameCount;
191 }
192 if (mReadBufferState > 0) {
193 ssize_t framesWritten = mPipeSink->write(mReadBuffer, mReadBufferState);
194 // FIXME This supports at most one fast capture client.
195 // To handle multiple clients this could be converted to an array,
196 // or with a lot more work the control block could be shared by all clients.
197 audio_track_cblk_t* cblk = current->mCblk;
198 if (cblk != NULL && framesWritten > 0) {
199 int32_t rear = cblk->u.mStreaming.mRear;
200 android_atomic_release_store(framesWritten + rear, &cblk->u.mStreaming.mRear);
201 cblk->mServer += framesWritten;
202 int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
203 if (!(old & CBLK_FUTEX_WAKE)) {
204 // client is never in server process, so don't use FUTEX_WAKE_PRIVATE
205 (void) syscall(__NR_futex, &cblk->mFutex, FUTEX_WAKE, 1);
206 }
207 }
208 }
209 }
210 }
211
212 } // namespace android
213